summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/gc/compartment-revived-gc.js
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/jit-test/tests/gc/compartment-revived-gc.js
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/jit-test/tests/gc/compartment-revived-gc.js')
-rw-r--r--js/src/jit-test/tests/gc/compartment-revived-gc.js133
1 files changed, 133 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/gc/compartment-revived-gc.js b/js/src/jit-test/tests/gc/compartment-revived-gc.js
new file mode 100644
index 0000000000..881f4a622a
--- /dev/null
+++ b/js/src/jit-test/tests/gc/compartment-revived-gc.js
@@ -0,0 +1,133 @@
+// Test 'compartment revived' GCs, where we do an extra GC if there are
+// compartments which we expected to die but were kept alive.
+
+// A global used as the destination for transplants.
+let transplantTargetGlobal = newGlobal();
+
+function didCompartmentRevivedGC() {
+ return performance.mozMemory.gc.lastStartReason === "COMPARTMENT_REVIVED";
+}
+
+function compartmentCount() {
+ let r = performance.mozMemory.gc.compartmentCount;
+ return r;
+}
+
+function startIncrementalGC() {
+ startgc(1);
+ while (gcstate() === "Prepare") {
+ gcslice(100, {dontStart: true});
+ }
+ assertEq(gcstate(), "Mark");
+}
+
+function finishIncrementalGC() {
+ while (gcstate() !== "NotActive") {
+ gcslice(100, {dontStart: true});
+ }
+ assertEq(gcstate(), "NotActive");
+}
+
+// Create a new compartment and global and return the global.
+function createCompartment() {
+ return newGlobal({newCompartment: true});
+}
+
+// Create a transplantable object and create a wrapper to it from a new
+// compartment. Return a function to transplant the target object.
+function createTransplantableWrapperTarget(wrapperGlobal) {
+ let {object: target, transplant} = transplantableObject();
+ wrapperGlobal.wrapper = target;
+ return transplant;
+}
+
+// Transplant an object to a new global by calling the transplant
+// function. This remaps all wrappers pointing to the target object,
+// potentially keeping dead compartments alive.
+function transplantTargetAndRemapWrappers(transplant) {
+ transplant(transplantTargetGlobal);
+}
+
+// Test no compartment revived GC triggered in normal cases.
+function testNormal() {
+ gc();
+ assertEq(didCompartmentRevivedGC(), false);
+
+ startIncrementalGC();
+ finishIncrementalGC();
+ assertEq(didCompartmentRevivedGC(), false);
+
+ let initialCount = compartmentCount();
+ createCompartment();
+ startIncrementalGC();
+ finishIncrementalGC();
+ assertEq(compartmentCount(), initialCount);
+}
+
+// Test compartment revived GC is triggered by wrapper remapping.
+function testCompartmentRevived1() {
+ let initialCount = compartmentCount();
+ let compartment = createCompartment();
+ let transplant = createTransplantableWrapperTarget(compartment);
+ compartment = null;
+
+ startIncrementalGC();
+ transplantTargetAndRemapWrappers(transplant);
+ finishIncrementalGC();
+
+ assertEq(didCompartmentRevivedGC(), true);
+ assertEq(compartmentCount(), initialCount);
+}
+
+// Test no compartment revived GC is triggered for compartments transitively
+// kept alive by black roots.
+function testCompartmentRevived2() {
+ let initialCount = compartmentCount();
+ let compartment = createCompartment();
+ let transplant = createTransplantableWrapperTarget(compartment);
+ let liveCompartment = createCompartment();
+ liveCompartment.wrapper = compartment;
+ compartment = null;
+
+ startIncrementalGC();
+ transplantTargetAndRemapWrappers(transplant);
+ finishIncrementalGC();
+
+ assertEq(didCompartmentRevivedGC(), false);
+ assertEq(compartmentCount(), initialCount + 2);
+
+ liveCompartment = null;
+ gc();
+
+ assertEq(compartmentCount(), initialCount);
+}
+
+// Test no compartment revived GC is triggered for compartments transitively
+// kept alive by gray roots.
+function testCompartmentRevived3() {
+ let initialCount = compartmentCount();
+ let compartment = createCompartment();
+ let transplant = createTransplantableWrapperTarget(compartment);
+ let liveCompartment = createCompartment();
+ liveCompartment.wrapper = compartment;
+ liveCompartment.eval('grayRoot()[0] = this');
+ liveCompartment = null;
+ gc();
+
+ startIncrementalGC();
+ transplantTargetAndRemapWrappers(transplant);
+ finishIncrementalGC();
+
+ assertEq(didCompartmentRevivedGC(), false);
+ assertEq(compartmentCount(), initialCount + 2);
+
+ // There's no easy way to clear gray roots for a compartment we don't have
+ // any reference to.
+}
+
+gczeal(0);
+
+testNormal();
+testCompartmentRevived1();
+testCompartmentRevived2();
+testCompartmentRevived3();