summaryrefslogtreecommitdiffstats
path: root/js/src/jsapi-tests/testDeduplication.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /js/src/jsapi-tests/testDeduplication.cpp
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/jsapi-tests/testDeduplication.cpp')
-rw-r--r--js/src/jsapi-tests/testDeduplication.cpp126
1 files changed, 126 insertions, 0 deletions
diff --git a/js/src/jsapi-tests/testDeduplication.cpp b/js/src/jsapi-tests/testDeduplication.cpp
new file mode 100644
index 0000000000..6ee3cb989d
--- /dev/null
+++ b/js/src/jsapi-tests/testDeduplication.cpp
@@ -0,0 +1,126 @@
+/* -*- 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 "gc/GC.h"
+
+#include "js/RootingAPI.h"
+#include "js/StableStringChars.h"
+#include "js/String.h" // JS::StringToLinearString
+
+#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::RootedString str(cx);
+ JS::RootedString dep(cx);
+ JS::RootedString depdep(cx);
+ JS::RootedString str2(cx);
+ JS::RootedString dep2(cx);
+ JS::RootedString depdep2(cx);
+
+ if (!cx->zone()->allocNurseryStrings()) {
+ // This test requires nursery-allocated strings, so that they will go
+ // through the deduplication pass during minor GC.
+ return true;
+ }
+
+ {
+ // This test checks the behavior when GC is performed after allocating
+ // all the following strings.
+ // GC shouldn't happen in between them, even in compacting jobs.
+ js::gc::AutoSuppressGC suppress(cx);
+
+ original = JS_NewStringCopyZ(cx, text);
+ CHECK(original);
+
+ // Create a chain of dependent strings, with a base string whose contents
+ // match `original`'s.
+ str = JS_NewStringCopyZ(cx, text);
+ CHECK(str && !str->isTenured());
+
+ dep = JS_NewDependentString(cx, str, 10, 100);
+ CHECK(dep && !dep->isTenured());
+
+ depdep = JS_NewDependentString(cx, dep, 10, 80);
+ CHECK(depdep && !depdep->isTenured());
+
+ // Repeat. This one will not be prevented from deduplication.
+ str2 = JS_NewStringCopyZ(cx, text);
+ CHECK(str2 && !str2->isTenured());
+
+ dep2 = JS_NewDependentString(cx, str2, 10, 100);
+ CHECK(dep2 && !dep2->isTenured());
+
+ depdep2 = JS_NewDependentString(cx, dep2, 10, 80);
+ CHECK(depdep2 && !depdep2->isTenured());
+ }
+
+ // Initializing an AutoStableStringChars with `depdep` will prevent the
+ // owner of its chars (`str`) from being deduplicated, but only if the
+ // chars are stored in the malloc heap. Force `str` to be nondeduplicatable
+ // unconditionally to avoid depending on the exact set of things that are
+ // enabled.
+ str->setNonDeduplicatable();
+ 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 `str2` and `original`. Or with
+ // `str`, since it could legitimately have been detected to be identical to
+ // the tenured `depdep` and deduplicated to that.
+ CHECK(SameChars(cx, depdep2, str2, 20) || SameChars(cx, depdep2, str, 20));
+ CHECK(SameChars(cx, depdep2, original, 20) ||
+ SameChars(cx, depdep2, str, 20));
+
+ return true;
+}
+END_TEST(testDeduplication_ASSC)