зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1655203 - Add tests for AutoStableStringChars and deduplication r=jonco
Differential Revision: https://phabricator.services.mozilla.com/D84872
This commit is contained in:
Родитель
fbee9129e1
Коммит
a637146e6b
|
@ -0,0 +1,39 @@
|
|||
// AutoStableStringChars needs to prevent the owner of its chars from being
|
||||
// deduplicated, even if they are held by a different string.
|
||||
|
||||
gczeal(0);
|
||||
|
||||
function makeExtensibleStrFrom(str) {
|
||||
var left = str.substr(0, str.length/2);
|
||||
var right = str.substr(str.length/2, str.length);
|
||||
var ropeStr = left + right;
|
||||
return ensureLinearString(ropeStr);
|
||||
}
|
||||
|
||||
// Make a string to deduplicate to.
|
||||
var original = makeExtensibleStrFrom('{ "phbbbbbbbbbbbbbbttt!!!!??": [1] }\n\n');
|
||||
|
||||
// Construct D2 -> D1 -> base
|
||||
var D2 = makeExtensibleStrFrom('{ "phbbbbbbbbbbbbbbttt!!!!??": [1] }');
|
||||
var D1 = newRope(D2, '\n', {nursery: true});
|
||||
ensureLinearString(D1);
|
||||
var base = newRope(D1, '\n', {nursery: true});
|
||||
ensureLinearString(base);
|
||||
|
||||
// Make an AutoStableStringChars(D2) and do a minor GC within it. (This will do
|
||||
// a major GC, but it'll start out with a minor GC.) `base` would get
|
||||
// deduplicated to `original`, if it weren't for AutoStableStringChars marking
|
||||
// all of D2, D1, and base non-deduplicatable.
|
||||
|
||||
// The first time JSON.parse runs, it will create several (14 in my test) GC
|
||||
// things before getting to the point where it does an allocation while holding
|
||||
// the chars pointer. Get them out of the way now.
|
||||
JSON.parse(D2);
|
||||
|
||||
// Cause a minor GC to happen during JSON.parse after AutoStableStringChars
|
||||
// gives up its pointer.
|
||||
schedulegc(1);
|
||||
JSON.parse(D2);
|
||||
|
||||
// Access `D2` to verify that it is not using the deduplicated chars.
|
||||
print(D2);
|
|
@ -0,0 +1,44 @@
|
|||
function str(c) {
|
||||
let s = c;
|
||||
for (let i = 0; i < 30; i++)
|
||||
s += c;
|
||||
ensureLinearString(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
function f() {
|
||||
// Create some slots to write into.
|
||||
const o = {owner: 'short1', s: 'short2'};
|
||||
|
||||
// Make a tenured rope.
|
||||
const r1 = str("a") + str("b");
|
||||
gc();
|
||||
|
||||
// Write the first instance of our duplicate string into one of the slots
|
||||
// (`owner`). This will be scanned first, and entered into deDupSet when
|
||||
// tenured.
|
||||
o.owner = ensureLinearString(str("a") + str("b") + str("c"));
|
||||
|
||||
// Make another rope with identical contents, with a tenured subtree.
|
||||
const r2 = r1 + str("c");
|
||||
|
||||
// Linearize the new rope, creating a new extensible string and a bunch of
|
||||
// dependent strings replacing the rest of the rope nodes.
|
||||
ensureLinearString(r2);
|
||||
|
||||
// Write the new rope into a slot, so that it will be scanned next during the
|
||||
// minor GC during traceSlots().
|
||||
o.s = r2;
|
||||
|
||||
// Do a nursery collection. o.owner will be tenured and inserted into
|
||||
// deDupSet. Then o.s aka r2 will be tenured. If things work correctly, r2
|
||||
// will be marked non-deduplicatable because it is the base of a tenured
|
||||
// string r1. If not, it will be deduplicated to o.owner.
|
||||
minorgc();
|
||||
|
||||
// Extract out that r1 child node. If its base was deduplicated, this will
|
||||
// assert because its chars have been freed.
|
||||
const s1 = r1.substr(0, 31);
|
||||
}
|
||||
|
||||
f();
|
|
@ -28,6 +28,7 @@ UNIFIED_SOURCES += [
|
|||
'testCompileUtf8.cpp',
|
||||
'testDateToLocaleString.cpp',
|
||||
'testDebugger.cpp',
|
||||
'testDeduplication.cpp',
|
||||
'testDeepFreeze.cpp',
|
||||
'testDefineGetterSetterNonEnumerable.cpp',
|
||||
'testDefineProperty.cpp',
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=8 sts=2 et sw=2 tw=80:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/StableStringChars.h"
|
||||
|
||||
#include "jsapi-tests/tests.h"
|
||||
|
||||
#include "vm/JSContext.h"
|
||||
#include "vm/StringType.h"
|
||||
|
||||
#include "vm/JSContext-inl.h"
|
||||
|
||||
static bool SameChars(JSContext* cx, JSString* str1, JSString* str2,
|
||||
size_t offset) {
|
||||
JS::AutoCheckCannotGC nogc(cx);
|
||||
|
||||
const JS::Latin1Char* chars1 =
|
||||
js::StringToLinearString(cx, str1)->latin1Chars(nogc);
|
||||
const JS::Latin1Char* chars2 =
|
||||
js::StringToLinearString(cx, str2)->latin1Chars(nogc);
|
||||
|
||||
return chars1 == chars2 + offset;
|
||||
}
|
||||
|
||||
BEGIN_TEST(testDeduplication_ASSC) {
|
||||
// Test with a long enough string to avoid inline chars allocation.
|
||||
const char text[] =
|
||||
"Andthebeastshallcomeforthsurroundedbyaroilingcloudofvengeance."
|
||||
"Thehouseoftheunbelieversshallberazedandtheyshallbescorchedtoth"
|
||||
"eearth.Theirtagsshallblinkuntiltheendofdays.";
|
||||
|
||||
// Create a string to deduplicate later strings to.
|
||||
JS::RootedString original(cx, JS_NewStringCopyZ(cx, text));
|
||||
CHECK(original);
|
||||
|
||||
// Create a chain of dependent strings, with a base string whose contents
|
||||
// match `original`'s.
|
||||
JS::RootedString str(cx, JS_NewStringCopyZ(cx, text));
|
||||
CHECK(str);
|
||||
|
||||
JS::RootedString dep(cx, JS_NewDependentString(cx, str, 10, 100));
|
||||
CHECK(str);
|
||||
|
||||
JS::RootedString depdep(cx, JS_NewDependentString(cx, dep, 10, 80));
|
||||
CHECK(str);
|
||||
|
||||
// Repeat. This one will not be prevented from deduplication.
|
||||
JS::RootedString str2(cx, JS_NewStringCopyZ(cx, text));
|
||||
CHECK(str);
|
||||
|
||||
JS::RootedString dep2(cx, JS_NewDependentString(cx, str2, 10, 100));
|
||||
CHECK(str);
|
||||
|
||||
JS::RootedString depdep2(cx, JS_NewDependentString(cx, dep2, 10, 80));
|
||||
CHECK(str);
|
||||
|
||||
// Initializing an AutoStableStringChars with `depdep` should prevent the
|
||||
// owner of its chars (`str`) from deduplication.
|
||||
JS::AutoStableStringChars stable(cx);
|
||||
CHECK(stable.init(cx, depdep));
|
||||
|
||||
const JS::Latin1Char* chars = stable.latin1Chars();
|
||||
CHECK(memcmp(chars, text + 20, 80 * sizeof(JS::Latin1Char)) == 0);
|
||||
|
||||
// `depdep` should share chars with `str` but not with `original`.
|
||||
CHECK(SameChars(cx, depdep, str, 20));
|
||||
CHECK(!SameChars(cx, depdep, original, 20));
|
||||
|
||||
// Same for `depdep2`.
|
||||
CHECK(SameChars(cx, depdep2, str2, 20));
|
||||
CHECK(!SameChars(cx, depdep2, original, 20));
|
||||
|
||||
// Do a minor GC that will deduplicate `str2` to `original`, and would have
|
||||
// deduplicated `str` as well if it weren't prevented by the
|
||||
// AutoStableStringChars.
|
||||
cx->minorGC(JS::GCReason::API);
|
||||
|
||||
// `depdep` should still share chars with `str` but not with `original`.
|
||||
CHECK(SameChars(cx, depdep, str, 20));
|
||||
CHECK(!SameChars(cx, depdep, original, 20));
|
||||
|
||||
// `depdep2` should now share chars with both `str` and `original`.
|
||||
CHECK(SameChars(cx, depdep2, str2, 20));
|
||||
CHECK(SameChars(cx, depdep2, original, 20));
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(testDeduplication_ASSC)
|
Загрузка…
Ссылка в новой задаче