tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 7eeae05a818cbd15cc869a1ef61db3e7f82cdccc
parent 98bcabadc0b781dbb6be2c0171c1951c3b1d34e0
Author: Jon Coppeard <jcoppeard@mozilla.com>
Date:   Sat,  1 Nov 2025 11:58:11 +0000

Bug 1994871 - Part 5: Add symbols to the CC graph r=mccr8

Differential Revision: https://phabricator.services.mozilla.com/D269957

Diffstat:
Mjs/public/TraceKind.h | 2+-
Mjs/xpconnect/tests/mochitest/test_weakmaps.html | 73++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Mxpcom/base/CycleCollectedJSRuntime.cpp | 6+++---
3 files changed, 54 insertions(+), 27 deletions(-)

diff --git a/js/public/TraceKind.h b/js/public/TraceKind.h @@ -96,7 +96,7 @@ struct MapTypeToTraceKind { D(Script, js::BaseScript, true, true) \ D(Shape, js::Shape, true, false) \ D(String, JSString, false, false) \ - D(Symbol, JS::Symbol, true, false) \ + D(Symbol, JS::Symbol, true, true) \ D(BigInt, JS::BigInt, false, false) \ D(RegExpShared, js::RegExpShared, true, true) \ D(GetterSetter, js::GetterSetter, true, true) \ diff --git a/js/xpconnect/tests/mochitest/test_weakmaps.html b/js/xpconnect/tests/mochitest/test_weakmaps.html @@ -42,24 +42,41 @@ function go() { must know the proper structure of the heap. */ - let make_gray_loop = function () { + let make_gray_loop_through = function (key) { let map = new WeakMap; let div = document.createElement("div"); - let key = {}; let obj = {m:map, k:key}; div.addEventListener("foo", function() { - // The code below doesn't matter (it won't run). Just pull a + // Entrain |obj| by referencing it from a closure attached to the + // element. The code below doesn't matter (it won't run). Just pull a // reference to obj. obj.k = 1; obj.m = "bar"; }); - //div.entrain = {m:map, k:key}; This is not sufficient to cause a leak in Fx9 map.set(key, div); return make_weak_ref(map); }; - let weakref = make_gray_loop(); + let make_gray_loop_through_shape = function () { + let key = Symbol(); + let map = new WeakMap; + let div = document.createElement("div"); + let obj = {m:map}; + obj[key] = 1; + div.addEventListener("foo", function() { + // Entrain |obj| by referencing it from a closure attached to the + // element. The code below doesn't matter (it won't run). Just pull a + // reference to obj. + obj.k = 1; + obj.m = "bar"; + }); + map.set(key, div); + return make_weak_ref(map); + }; + let weakref_through_object = make_gray_loop_through({}); + let weakref_through_symbol = make_gray_loop_through(Symbol()); + let weakref_through_shape = make_gray_loop_through_shape(); /* Combinations of live and dead gray maps/keys. */ let basic_weak_ref = null; @@ -224,34 +241,44 @@ function go() { // We're out of ideas for unpreservable natives, now that just about // everything is on webidl, so just don't test those. - /* set up for running precise GC/CC then checking the results */ + SpecialPowers.forceGC(); - SpecialPowers.exactGC(function () { - SpecialPowers.forceCC(); - SpecialPowers.forceGC(); - SpecialPowers.forceGC(); + // GC on its own can't collect these cycles. + ok(!weak_ref_dead(weakref_through_object), + "Garbage gray cycle through object should be alive."); + ok(!weak_ref_dead(weakref_through_symbol), + "Garbage gray cycle through symbol should be alive."); + ok(!weak_ref_dead(weakref_through_shape), + "Garbage gray cycle through shape should be alive."); - ok(weak_ref_dead(weakref), "Garbage gray cycle should be collected."); + SpecialPowers.forceCC(); + SpecialPowers.forceGC(); - check_nested_cc_maps(); + ok(weak_ref_dead(weakref_through_object), + "Garbage gray cycle through object should be collected."); + ok(weak_ref_dead(weakref_through_symbol), + "Garbage gray cycle through symbol should be collected."); + ok(weak_ref_dead(weakref_through_shape), + "Garbage gray cycle through shape should be collected."); - is(SpecialPowers.nondeterministicGetWeakMapKeys(garbage_map).length, 0, "Chained garbage weak map entries should not leak."); + check_nested_cc_maps(); - check_basic_unit(); + is(SpecialPowers.nondeterministicGetWeakMapKeys(garbage_map).length, 0, + "Chained garbage weak map entries should not leak."); - // fixed by Bug 680937 - is(SpecialPowers.nondeterministicGetWeakMapKeys(wn_garbage_map).length, 0, - "Chained garbage WN weak map entries should not leak."); + check_basic_unit(); - // fixed by Bug 680937 - is(SpecialPowers.nondeterministicGetWeakMapKeys(wn_live_map).length, 1, - "Live weak map wrapped native key should not be removed."); + // fixed by Bug 680937 + is(SpecialPowers.nondeterministicGetWeakMapKeys(wn_garbage_map).length, 0, + "Chained garbage WN weak map entries should not leak."); - ok(wn_live_map.has(get_live_dom()), "Live map should have live dom."); + // fixed by Bug 680937 + is(SpecialPowers.nondeterministicGetWeakMapKeys(wn_live_map).length, 1, + "Live weak map wrapped native key should not be removed."); - SimpleTest.finish(); - }); + ok(wn_live_map.has(get_live_dom()), "Live map should have live dom."); + SimpleTest.finish(); } </script> </head> diff --git a/xpcom/base/CycleCollectedJSRuntime.cpp b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -400,9 +400,9 @@ struct TraversalTracer : public JS::CallbackTracer { }; void TraversalTracer::onChild(JS::GCCellPtr aThing, const char* name) { - // Checking strings and symbols for being gray is rather slow, and we don't - // need either of them for the cycle collector. - if (aThing.is<JSString>() || aThing.is<JS::Symbol>()) { + // Checking strings for being gray is rather slow, and we don't need them for + // the cycle collector. + if (aThing.is<JSString>()) { return; }