commit 12bf2b1c5311094236999130012b1d1b6e3846f9
parent 0c8cb1c7fba82367dd0611d62fc2d0ed7e446ef3
Author: pstanciu <pstanciu@mozilla.com>
Date: Thu, 30 Oct 2025 13:02:15 +0200
Revert "Bug 1997118 - Mark gray bits as invalid if we abort GC during marking r=sfink" for causing assertion failure in Bug 1997268
This reverts commit 7a852d3774bf3ab127c44b5a4859326450100d78.
Diffstat:
5 files changed, 3 insertions(+), 112 deletions(-)
diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp
@@ -3264,12 +3264,6 @@ static bool NondeterministicGetWeakMapKeys(JSContext* cx, unsigned argc,
return true;
}
-static bool GrayBitsValid(JSContext* cx, unsigned argc, Value* vp) {
- CallArgs args = CallArgsFromVp(argc, vp);
- args.rval().setBoolean(cx->runtime()->gc.areGrayBitsValid());
- return true;
-}
-
static bool SetGrayBitsInvalid(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
cx->runtime()->gc.setGrayBitsInvalid();
@@ -10413,10 +10407,6 @@ gc::ZealModeHelpText),
"nondeterministicGetWeakMapKeys(weakmap)",
" Return an array of the keys in the given WeakMap."),
- JS_FN_HELP("grayBitsValid", GrayBitsValid, 0, 0,
-"grayBitsValid()",
-" Return whether the gray bits state is valid."),
-
JS_FN_HELP("setGrayBitsInvalid", SetGrayBitsInvalid, 0, 0,
"setGrayBitsInvalid()",
" Set the gray bits state to invalid."),
diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp
@@ -3803,11 +3803,6 @@ GCRuntime::IncrementalResult GCRuntime::resetIncrementalGC(
resetGrayList(c);
}
- // The gray marking state may not be valid. We depend on the mark stack to
- // do gray unmarking in zones that are being marked by the GC and we've
- // just cancelled that part way through.
- setGrayBitsInvalid();
-
// Wait for sweeping of nursery owned sized allocations to finish.
nursery().joinSweepTask();
diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp
@@ -2929,11 +2929,6 @@ void UnmarkGrayTracer::onChild(JS::GCCellPtr thing, const char* name) {
void UnmarkGrayTracer::unmark(JS::GCCellPtr cell) {
MOZ_ASSERT(stack.empty());
- GCRuntime* gc = &runtime()->gc;
- if (!gc->areGrayBitsValid()) {
- return;
- }
-
onChild(cell, "unmarking root");
while (!stack.empty() && !oom) {
@@ -2944,7 +2939,8 @@ void UnmarkGrayTracer::unmark(JS::GCCellPtr cell) {
// If we run out of memory, we take a drastic measure: require that we
// GC again before the next CC.
stack.clear();
- gc->setGrayBitsInvalid();
+ runtime()->gc.setGrayBitsInvalid();
+ return;
}
}
diff --git a/js/src/jit-test/tests/gc/gray-unmarking.js b/js/src/jit-test/tests/gc/gray-unmarking.js
@@ -1,89 +0,0 @@
-// Test interaction of gray marking / cross zone pointers / aborted GC marking.
-
-gczeal(0);
-
-gc();
-assertEq(grayBitsValid(), true);
-
-// Create some globals in different zones.
-let g1 = newGlobal({newCompartment: true});
-let g2 = newGlobal({newCompartment: true});
-let g3 = newGlobal({newCompartment: true});
-
-// Set up a linked list of objects in different zones: a --> b --> c
-g1.eval('var a = {}');
-g2.eval('var b = {}');
-g3.eval('var c = {}');
-g1.a.next = g2.b;
-g2.b.next = g3.c;
-
-// Observe mark state of the objects and remove extra references from the globals.
-g1.eval('addMarkObservers([a])');
-g2.eval('addMarkObservers([b])');
-g3.eval('addMarkObservers([c])');
-g2.b = undefined;
-g3.c = undefined;
-
-function checkMarks(a, b, c) {
- assertEq(getMarks().join(", "), [a, b, c].join(", "));
-}
-
-// Check GC initially marks everything black.
-gc();
-checkMarks("black", "black", "black");
-
-// Replace root with a gray one and check GC marks everything gray.
-g1.eval('grayRoot()[0] = a');
-g1.a = undefined;
-gc();
-checkMarks("gray", "gray", "gray");
-
-// Read the gray root and check gray unmarking marks everything black again.
-g1.eval('grayRoot()[0]');
-checkMarks("black", "black", "black");
-
-// Reset everything to gray.
-gc();
-checkMarks("gray", "gray", "gray");
-
-// Start marking zone 2.
-schedulezone(g2);
-startgc(10);
-while (gcstate() === "Prepare" || gcstate() === "MarkRoots") {
- gcslice(10);
-}
-assertEq(gcstate(), "Mark");
-assertEq(gcstate(g1), "NoGC");
-assertEq(gcstate(g2), "MarkBlackOnly");
-assertEq(gcstate(g3), "NoGC");
-
-// Check zone 2's mark bits have been cleared.
-checkMarks("gray", "unmarked", "gray");
-
-// Gray unmarking stops at the zone that is being mraked
-g1.eval('grayRoot()[0]');
-checkMarks("black", "black", "gray");
-
-// GC marking handles the gray unmarking by propagaing b's mark state.
-finishgc();
-assertEq(grayBitsValid(), true);
-checkMarks("black", "black", "black");
-
-// Reset everything to gray.
-gc();
-checkMarks("gray", "gray", "gray");
-
-// Repeat the previous test but abort marking after unmarking a. c is
-// left as 'gray' (incorrect) but the gray marking state is marked as invalid.
-schedulezone(g2);
-startgc(10);
-while (gcstate() === "Prepare" || gcstate() === "MarkRoots") {
- gcslice(10);
-}
-assertEq(gcstate(), "Mark");
-checkMarks("gray", "unmarked", "gray");
-g1.eval('grayRoot()[0]');
-assertEq(grayBitsValid(), true);
-abortgc();
-assertEq(grayBitsValid(), false);
-checkMarks("black", "black", "gray");
diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp
@@ -3470,8 +3470,7 @@ static void SendNeedGCTelemetry(bool needGC) {
// reachable only from XPConnect roots that might participate in cycles.
//
// That data might not currently be valid, requiring a GC to restore it. This is
-// rare in practice and is caused by an OOM during gray unmarking or aborting GC
-// part way through marking.
+// rare in practice and is caused by an OOM during gray unmarking.
//
// We also force GCs on shutdown to collect cycles involving both DOM and JS,
// and in WantAllTraces CCs to prevent hijinks from ForgetSkippable and