testDeduplication.cpp (4999B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 */ 4 /* This Source Code Form is subject to the terms of the Mozilla Public 5 * License, v. 2.0. If a copy of the MPL was not distributed with this 6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 7 8 #include <string.h> 9 10 #include "gc/GC.h" 11 12 #include "js/RootingAPI.h" 13 #include "js/StableStringChars.h" 14 #include "js/String.h" // JS::StringToLinearString 15 16 #include "jsapi-tests/tests.h" 17 18 #include "vm/JSContext.h" 19 #include "vm/StringType.h" 20 21 #include "vm/JSContext-inl.h" 22 23 static bool SameChars(JSContext* cx, JSString* str1, JSString* str2, 24 size_t offset) { 25 JS::AutoCheckCannotGC nogc(cx); 26 27 const JS::Latin1Char* chars1 = 28 JS::StringToLinearString(cx, str1)->latin1Chars(nogc); 29 const JS::Latin1Char* chars2 = 30 JS::StringToLinearString(cx, str2)->latin1Chars(nogc); 31 32 return chars1 == chars2 + offset; 33 } 34 35 BEGIN_TEST(testDeduplication_ASSC) { 36 AutoGCParameter disableSemispace(cx, JSGC_SEMISPACE_NURSERY_ENABLED, 0); 37 38 // Test with a long enough string to avoid inline chars allocation. 39 const char text[] = 40 "Andthebeastshallcomeforthsurroundedbyaroilingcloudofvengeance." 41 "Thehouseoftheunbelieversshallberazedandtheyshallbescorchedtoth" 42 "eearth.Theirtagsshallblinkuntiltheendofdays."; 43 44 // Create a string to deduplicate later strings to. 45 JS::RootedString original(cx); 46 JS::RootedString str(cx); 47 JS::RootedString dep(cx); 48 JS::RootedString depdep(cx); 49 JS::RootedString str2(cx); 50 JS::RootedString dep2(cx); 51 JS::RootedString depdep2(cx); 52 53 if (!cx->zone()->allocNurseryStrings()) { 54 // This test requires nursery-allocated strings, so that they will go 55 // through the deduplication pass during minor GC. 56 return true; 57 } 58 59 { 60 // This test checks the behavior when GC is performed after allocating 61 // all the following strings. 62 // GC shouldn't happen in between them, even in compacting jobs. 63 js::gc::AutoSuppressGC suppress(cx); 64 65 original = JS_NewStringCopyZ(cx, text); 66 CHECK(original); 67 68 // Create a chain of dependent strings, with a base string whose contents 69 // match `original`'s. 70 str = JS_NewStringCopyZ(cx, text); 71 CHECK(str && !str->isTenured()); 72 73 dep = JS_NewDependentString(cx, str, 10, 100); 74 CHECK(dep && !dep->isTenured()); 75 76 depdep = JS_NewDependentString(cx, dep, 10, 80); 77 CHECK(depdep && !depdep->isTenured()); 78 79 // Repeat. This one will not be prevented from deduplication. 80 str2 = JS_NewStringCopyZ(cx, text); 81 CHECK(str2 && !str2->isTenured()); 82 83 dep2 = JS_NewDependentString(cx, str2, 10, 100); 84 CHECK(dep2 && !dep2->isTenured()); 85 86 depdep2 = JS_NewDependentString(cx, dep2, 10, 80); 87 CHECK(depdep2 && !depdep2->isTenured()); 88 } 89 90 // Initializing an AutoStableStringChars with `depdep` will prevent the 91 // owner of its chars (`str`) from being deduplicated, but only if the 92 // chars are stored in the malloc heap. Force `str` to be nondeduplicatable 93 // unconditionally to avoid depending on the exact set of things that are 94 // enabled. 95 str->setNonDeduplicatable(); 96 JS::AutoStableStringChars stable(cx); 97 CHECK(stable.init(cx, depdep)); 98 99 CHECK(stable.latin1Range().length() == 80); 100 101 const JS::Latin1Char* chars = stable.latin1Chars(); 102 CHECK(memcmp(chars, text + 20, 80 * sizeof(JS::Latin1Char)) == 0); 103 104 // `depdep` should share chars with `str` but not with `original`. 105 CHECK(SameChars(cx, depdep, str, 20)); 106 CHECK(!SameChars(cx, depdep, original, 20)); 107 108 // Same for `depdep2`. 109 CHECK(SameChars(cx, depdep2, str2, 20)); 110 CHECK(!SameChars(cx, depdep2, original, 20)); 111 112 // Do a minor GC that will deduplicate `str2` to `original`, and would have 113 // deduplicated `str` as well if it weren't prevented by the 114 // AutoStableStringChars. 115 cx->minorGC(JS::GCReason::API); 116 117 // `depdep` should still share chars with `str` but not with `original`. 118 CHECK(SameChars(cx, depdep, str, 20)); 119 CHECK(!SameChars(cx, depdep, original, 20)); 120 121 // `depdep2` should now share chars with both `str2` and `original`. Or with 122 // `str`, since it could legitimately have been detected to be identical to 123 // the tenured `depdep` and deduplicated to that. 124 CHECK(SameChars(cx, depdep2, str2, 20) || SameChars(cx, depdep2, str, 20)); 125 126 // TODO: this currently breaks because we are more conservative than we need 127 // to be with handling the DEPENDED_ON_BIT and deduplication. This will be 128 // fixed in bug 1900142 129 // CHECK(SameChars(cx, depdep2, original, 20) || 130 // SameChars(cx, depdep2, str, 20)); 131 132 // Make sure AutoStableStringChars uses the correct length when strings are 133 // tenured. 134 JS::AutoStableStringChars stable2(cx); 135 CHECK(stable2.init(cx, depdep)); 136 // This should get the length from the dependent string, not the string that 137 // owns its data. 138 CHECK(stable2.latin1Range().length() == 80); 139 140 return true; 141 } 142 END_TEST(testDeduplication_ASSC)