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:
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); }