tor-browser

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

commit cf425e35dc97a27dec9cf0acd43166d7edf63383
parent f7ad945399ecc1cae4999bb2e0f74ff940b21cdb
Author: Steve Fink <sfink@mozilla.com>
Date:   Mon, 17 Nov 2025 21:37:11 +0000

Bug 1999684 - Nursery keys/values never become ephemerons, and fix theoretical problem with tenured CCW -> nursery delegate r=jonco

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

Diffstat:
Mjs/src/gc/WeakMap-inl.h | 11+++++++++--
Mjs/src/gc/WeakMap.cpp | 28++++++++++++++++++++++------
Mjs/src/gc/WeakMap.h | 6+++---
3 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/js/src/gc/WeakMap-inl.h b/js/src/gc/WeakMap-inl.h @@ -239,13 +239,20 @@ bool WeakMap<K, V, AP>::markEntry(GCMarker* marker, gc::CellColor mapColor, // the key is marked. If the key has a delegate, also add an edge to // ensure the key is marked if the delegate is marked. + // Nursery values are added to the store buffer when writing them into + // the entry (via HeapPtr), so they will always get tenured. There's no + // need for a key->value ephemeron to keep them alive via the WeakMap. gc::TenuredCell* tenuredValue = nullptr; if (cellValue && cellValue->isTenured()) { tenuredValue = &cellValue->asTenured(); } - if (!this->addEphemeronEdgesForEntry(AsMarkColor(mapColor), keyCell, - delegate, tenuredValue)) { + // Nursery key is treated as black, so cannot be less marked than the map. + MOZ_ASSERT(keyCell->isTenured()); + + if (!this->addEphemeronEdgesForEntry(AsMarkColor(mapColor), + &keyCell->asTenured(), delegate, + tenuredValue)) { marker->abortLinearWeakMarking(); } } diff --git a/js/src/gc/WeakMap.cpp b/js/src/gc/WeakMap.cpp @@ -12,6 +12,7 @@ #include "vm/JSObject.h" #include "gc/Marking-inl.h" +#include "gc/StoreBuffer-inl.h" using namespace js; using namespace js::gc; @@ -64,11 +65,26 @@ bool WeakMapBase::markMap(MarkColor markColor) { } } -bool WeakMapBase::addEphemeronEdgesForEntry(MarkColor mapColor, Cell* key, - Cell* delegate, +bool WeakMapBase::addEphemeronEdgesForEntry(MarkColor mapColor, + TenuredCell* key, Cell* delegate, TenuredCell* value) { - if (delegate && !addEphemeronEdge(mapColor, delegate, key)) { - return false; + if (delegate) { + if (!delegate->isTenured()) { + MOZ_ASSERT(false); + // This case is probably not possible, or wasn't at the time of this + // writing. It requires a tenured wrapper with a nursery wrappee delegate, + // which is tough to create given that the wrapper has to be created after + // its target, and in fact appears impossible because the delegate has to + // be created after the GC begins to avoid being tenured at the beginning + // of the GC, and adding the key to the weakmap will mark the key via a + // pre-barrier. But still, handling this case is straightforward: + + // The delegate is already being kept alive in a minor GC since it has an + // edge from a tenured cell (the key). Make sure the key stays alive too. + delegate->storeBuffer()->putWholeCell(key); + } else if (!addEphemeronEdge(mapColor, &delegate->asTenured(), key)) { + return false; + } } if (value && !addEphemeronEdge(mapColor, key, value)) { @@ -78,8 +94,8 @@ bool WeakMapBase::addEphemeronEdgesForEntry(MarkColor mapColor, Cell* key, return true; } -bool WeakMapBase::addEphemeronEdge(MarkColor color, gc::Cell* src, - gc::Cell* dst) { +bool WeakMapBase::addEphemeronEdge(MarkColor color, gc::TenuredCell* src, + gc::TenuredCell* dst) { // Add an implicit edge from |src| to |dst|. auto& edgeTable = src->zone()->gcEphemeronEdges(src); diff --git a/js/src/gc/WeakMap.h b/js/src/gc/WeakMap.h @@ -188,11 +188,11 @@ class WeakMapBase : public mozilla::LinkedListElement<WeakMapBase> { // value getting marked. Insert the necessary edges into the appropriate // zone's gcEphemeronEdges or gcNurseryEphemeronEdges tables. [[nodiscard]] bool addEphemeronEdgesForEntry(gc::MarkColor mapColor, - gc::Cell* key, + gc::TenuredCell* key, gc::Cell* delegate, gc::TenuredCell* value); - [[nodiscard]] bool addEphemeronEdge(gc::MarkColor color, gc::Cell* src, - gc::Cell* dst); + [[nodiscard]] bool addEphemeronEdge(gc::MarkColor color, gc::TenuredCell* src, + gc::TenuredCell* dst); gc::CellColor mapColor() const { return gc::CellColor(uint32_t(mapColor_)); } void setMapColor(gc::CellColor newColor) { mapColor_ = uint32_t(newColor); }