commit 4f9e513a488d238d7c090e3ecbd09e51b54631c2
parent beee3e9ab8ff427d25aafb6cfa55bc23a4590ef0
Author: Jon Coppeard <jcoppeard@mozilla.com>
Date: Mon, 13 Oct 2025 13:35:09 +0000
Bug 1993183 - Part 2: Add WeakMap alloc policy template parameter r=sfink
Differential Revision: https://phabricator.services.mozilla.com/D267938
Diffstat:
10 files changed, 51 insertions(+), 45 deletions(-)
diff --git a/js/src/builtin/WeakMapObject.h b/js/src/builtin/WeakMapObject.h
@@ -17,7 +17,7 @@ class WeakCollectionObject : public NativeObject {
public:
enum { DataSlot, SlotCount };
- using Map = WeakMap<Value, Value>;
+ using Map = WeakMap<Value, Value, ZoneAllocPolicy>;
Map* getMap() { return maybePtrFromReservedSlot<Map>(DataSlot); }
size_t sizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf);
diff --git a/js/src/debugger/DebugScript.h b/js/src/debugger/DebugScript.h
@@ -150,7 +150,8 @@ class DebugScriptObject : public NativeObject {
};
// A weak map from JSScripts to DebugScriptObjects.
-class DebugScriptMap : public WeakMap<JSScript*, DebugScriptObject*> {
+class DebugScriptMap
+ : public WeakMap<JSScript*, DebugScriptObject*, ZoneAllocPolicy> {
public:
explicit DebugScriptMap(JSContext* cx) : WeakMap(cx) {}
};
diff --git a/js/src/debugger/Debugger.h b/js/src/debugger/Debugger.h
@@ -336,7 +336,7 @@ extern void CheckDebuggeeThing(JSObject* obj, bool invisibleOk);
* beacomes a debuggee again later, new Frame objects are created.)
*/
template <class Referent, class Wrapper, bool InvisibleKeysOk = false>
-class DebuggerWeakMap : private WeakMap<Referent*, Wrapper*> {
+class DebuggerWeakMap : private WeakMap<Referent*, Wrapper*, ZoneAllocPolicy> {
private:
using Key = Referent*;
using Value = Wrapper*;
@@ -344,7 +344,7 @@ class DebuggerWeakMap : private WeakMap<Referent*, Wrapper*> {
JS::Compartment* compartment;
public:
- using Base = WeakMap<Key, Value>;
+ using Base = WeakMap<Key, Value, ZoneAllocPolicy>;
using ReferentType = Referent;
using WrapperType = Wrapper;
diff --git a/js/src/gc/WeakMap-inl.h b/js/src/gc/WeakMap-inl.h
@@ -92,8 +92,8 @@ static inline JSObject* GetDelegate(const T& key) {
// were in different zones, then we could have a case where the map zone is not
// collecting but the value zone is, and incorrectly free a value that is
// reachable solely through weakmaps.
-template <class K, class V>
-void WeakMap<K, V>::assertMapIsSameZoneWithValue(const BarrieredValue& v) {
+template <class K, class V, class AP>
+void WeakMap<K, V, AP>::assertMapIsSameZoneWithValue(const BarrieredValue& v) {
#ifdef DEBUG
gc::Cell* cell = gc::ToMarkable(v);
if (cell) {
@@ -103,12 +103,12 @@ void WeakMap<K, V>::assertMapIsSameZoneWithValue(const BarrieredValue& v) {
#endif
}
-template <class K, class V>
-WeakMap<K, V>::WeakMap(JSContext* cx, JSObject* memOf)
+template <class K, class V, class AP>
+WeakMap<K, V, AP>::WeakMap(JSContext* cx, JSObject* memOf)
: WeakMap(cx->zone(), memOf) {}
-template <class K, class V>
-WeakMap<K, V>::WeakMap(JS::Zone* zone, JSObject* memOf)
+template <class K, class V, class AP>
+WeakMap<K, V, AP>::WeakMap(JS::Zone* zone, JSObject* memOf)
: WeakMapBase(memOf, zone), map_(zone) {
static_assert(std::is_same_v<typename RemoveBarrier<K>::Type, K>);
static_assert(std::is_same_v<typename RemoveBarrier<V>::Type, V>);
@@ -129,8 +129,8 @@ WeakMap<K, V>::WeakMap(JS::Zone* zone, JSObject* memOf)
}
}
-template <class K, class V>
-WeakMap<K, V>::~WeakMap() {
+template <class K, class V, class AP>
+WeakMap<K, V, AP>::~WeakMap() {
#ifdef DEBUG
// Weak maps store their data in an unbarriered map (|map_|) meaning that no
// barriers are run on destruction. This is safe because:
@@ -162,10 +162,10 @@ WeakMap<K, V>::~WeakMap() {
// Optionally adds edges to the ephemeron edges table for any keys (or
// delegates) where future changes to their mark color would require marking the
// value (or the key).
-template <class K, class V>
-bool WeakMap<K, V>::markEntry(GCMarker* marker, gc::CellColor mapColor,
- BarrieredKey& key, BarrieredValue& value,
- bool populateWeakKeysTable) {
+template <class K, class V, class AP>
+bool WeakMap<K, V, AP>::markEntry(GCMarker* marker, gc::CellColor mapColor,
+ BarrieredKey& key, BarrieredValue& value,
+ bool populateWeakKeysTable) {
#ifdef DEBUG
MOZ_ASSERT(IsMarked(mapColor));
if (marker->isParallelMarking()) {
@@ -253,8 +253,8 @@ bool WeakMap<K, V>::markEntry(GCMarker* marker, gc::CellColor mapColor,
return marked;
}
-template <class K, class V>
-void WeakMap<K, V>::trace(JSTracer* trc) {
+template <class K, class V, class AP>
+void WeakMap<K, V, AP>::trace(JSTracer* trc) {
MOZ_ASSERT(isInList());
TraceNullableEdge(trc, &memberOf, "WeakMap owner");
@@ -286,8 +286,8 @@ void WeakMap<K, V>::trace(JSTracer* trc) {
}
}
-template <class K, class V>
-bool WeakMap<K, V>::markEntries(GCMarker* marker) {
+template <class K, class V, class AP>
+bool WeakMap<K, V, AP>::markEntries(GCMarker* marker) {
// This method is called whenever the map's mark color changes. Mark values
// (and keys with delegates) as required for the new color and populate the
// ephemeron edges if we're in incremental marking mode.
@@ -321,8 +321,10 @@ bool WeakMap<K, V>::markEntries(GCMarker* marker) {
return markedAny;
}
-template <class K, class V>
-void WeakMap<K, V>::traceWeakEdges(JSTracer* trc) {
+template <class K, class V, class AP>
+void WeakMap<K, V, AP>::traceWeakEdges(JSTracer* trc) {
+ MOZ_ASSERT(zone()->isGCSweeping());
+
// Scan the map, removing all entries whose keys remain unmarked. Rebuild
// cached key state at the same time.
mayHaveSymbolKeys = false;
@@ -343,8 +345,8 @@ void WeakMap<K, V>::traceWeakEdges(JSTracer* trc) {
}
// memberOf can be nullptr, which means that the map is not part of a JSObject.
-template <class K, class V>
-void WeakMap<K, V>::traceMappings(WeakMapTracer* tracer) {
+template <class K, class V, class AP>
+void WeakMap<K, V, AP>::traceMappings(WeakMapTracer* tracer) {
for (Range r = all(); !r.empty(); r.popFront()) {
gc::Cell* key = gc::ToMarkable(r.front().key());
gc::Cell* value = gc::ToMarkable(r.front().value());
@@ -355,8 +357,8 @@ void WeakMap<K, V>::traceMappings(WeakMapTracer* tracer) {
}
}
-template <class K, class V>
-bool WeakMap<K, V>::findSweepGroupEdges(Zone* atomsZone) {
+template <class K, class V, class AP>
+bool WeakMap<K, V, AP>::findSweepGroupEdges(Zone* atomsZone) {
// For weakmap keys with delegates in a different zone, add a zone edge to
// ensure that the delegate zone finishes marking before the key zone.
@@ -404,14 +406,15 @@ bool WeakMap<K, V>::findSweepGroupEdges(Zone* atomsZone) {
return true;
}
-template <class K, class V>
-size_t WeakMap<K, V>::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) {
+template <class K, class V, class AP>
+size_t WeakMap<K, V, AP>::sizeOfIncludingThis(
+ mozilla::MallocSizeOf mallocSizeOf) {
return mallocSizeOf(this) + shallowSizeOfExcludingThis(mallocSizeOf);
}
#if DEBUG
-template <class K, class V>
-void WeakMap<K, V>::assertEntriesNotAboutToBeFinalized() {
+template <class K, class V, class AP>
+void WeakMap<K, V, AP>::assertEntriesNotAboutToBeFinalized() {
for (Range r = all(); !r.empty(); r.popFront()) {
K k = r.front().key();
MOZ_ASSERT(!gc::IsAboutToBeFinalizedUnbarriered(k));
@@ -426,8 +429,8 @@ void WeakMap<K, V>::assertEntriesNotAboutToBeFinalized() {
#endif
#ifdef JS_GC_ZEAL
-template <class K, class V>
-bool WeakMap<K, V>::checkMarking() const {
+template <class K, class V, class AP>
+bool WeakMap<K, V, AP>::checkMarking() const {
bool ok = true;
for (Range r = all(); !r.empty(); r.popFront()) {
gc::Cell* key = gc::ToMarkable(r.front().key());
@@ -442,8 +445,8 @@ bool WeakMap<K, V>::checkMarking() const {
#endif
#ifdef JSGC_HASH_TABLE_CHECKS
-template <class K, class V>
-void WeakMap<K, V>::checkAfterMovingGC() const {
+template <class K, class V, class AP>
+void WeakMap<K, V, AP>::checkAfterMovingGC() const {
for (Range r = all(); !r.empty(); r.popFront()) {
gc::Cell* key = gc::ToMarkable(r.front().key());
gc::Cell* value = gc::ToMarkable(r.front().value());
diff --git a/js/src/gc/WeakMap.cpp b/js/src/gc/WeakMap.cpp
@@ -188,5 +188,5 @@ void WeakMapBase::restoreMarkedWeakMaps(WeakMapColors& markedWeakMaps) {
}
namespace js {
-template class WeakMap<JSObject*, JSObject*>;
+template class WeakMap<JSObject*, JSObject*, ZoneAllocPolicy>;
} // namespace js
diff --git a/js/src/gc/WeakMap.h b/js/src/gc/WeakMap.h
@@ -203,15 +203,15 @@ class WeakMapBase : public mozilla::LinkedListElement<WeakMapBase> {
template <typename Key>
struct WeakMapKeyHasher : public StableCellHasher<HeapPtr<Key>> {};
-template <class Key, class Value>
+template <class Key, class Value, class AllocPolicy>
class WeakMap : public WeakMapBase {
using BarrieredKey = HeapPtr<Key>;
using BarrieredValue = HeapPtr<Value>;
- using Map = HashMap<HeapPtr<Key>, HeapPtr<Value>, WeakMapKeyHasher<Key>,
- ZoneAllocPolicy>;
+ using Map =
+ HashMap<HeapPtr<Key>, HeapPtr<Value>, WeakMapKeyHasher<Key>, AllocPolicy>;
using UnbarrieredMap =
- HashMap<Key, Value, StableCellHasher<Key>, ZoneAllocPolicy>;
+ HashMap<Key, Value, StableCellHasher<Key>, AllocPolicy>;
UnbarrieredMap map_; // Barriers are added by |map()| accessor.
diff --git a/js/src/gc/WeakMapPtr.cpp b/js/src/gc/WeakMapPtr.cpp
@@ -34,7 +34,7 @@ template <typename K, typename V>
struct Utils {
using KeyType = K;
using ValueType = V;
- using Type = WeakMap<KeyType, ValueType>;
+ using Type = WeakMap<KeyType, ValueType, ZoneAllocPolicy>;
using PtrType = Type*;
static PtrType cast(void* ptr) { return static_cast<PtrType>(ptr); }
};
diff --git a/js/src/jsapi-tests/testGCGrayMarking.cpp b/js/src/jsapi-tests/testGCGrayMarking.cpp
@@ -26,8 +26,9 @@ static constexpr CellColor MarkedCellColors[] = {CellColor::Gray,
namespace js {
-struct GCManagedObjectWeakMap : public WeakMap<JSObject*, JSObject*> {
- using Base = WeakMap<JSObject*, JSObject*>;
+struct GCManagedObjectWeakMap
+ : public WeakMap<JSObject*, JSObject*, ZoneAllocPolicy> {
+ using Base = WeakMap<JSObject*, JSObject*, ZoneAllocPolicy>;
using Base::Base;
};
diff --git a/js/src/vm/EnvironmentObject.h b/js/src/vm/EnvironmentObject.h
@@ -1470,7 +1470,7 @@ class DebugEnvironments {
Zone* zone_;
/* The map from (non-debug) environments to debug environments. */
- using ProxiedEnvironmentsMap = WeakMap<JSObject*, JSObject*>;
+ using ProxiedEnvironmentsMap = WeakMap<JSObject*, JSObject*, ZoneAllocPolicy>;
ProxiedEnvironmentsMap proxiedEnvs;
/*
diff --git a/js/src/vm/Realm.h b/js/src/vm/Realm.h
@@ -240,7 +240,8 @@ class ObjectRealm {
// All non-syntactic lexical environments in the realm. These are kept in a
// map because when loading scripts into a non-syntactic environment, we
// need to use the same lexical environment to persist lexical bindings.
- using NonSyntacticLexialEnvironmentsMap = WeakMap<JSObject*, JSObject*>;
+ using NonSyntacticLexialEnvironmentsMap =
+ WeakMap<JSObject*, JSObject*, ZoneAllocPolicy>;
js::UniquePtr<NonSyntacticLexialEnvironmentsMap>
nonSyntacticLexicalEnvironments_;
@@ -253,7 +254,7 @@ class ObjectRealm {
// Keep track of the metadata objects which can be associated with each JS
// object. Both keys and values are in this realm.
- using ObjectMetadataTable = WeakMap<JSObject*, JSObject*>;
+ using ObjectMetadataTable = WeakMap<JSObject*, JSObject*, ZoneAllocPolicy>;
js::UniquePtr<ObjectMetadataTable> objectMetadataTable;
using IteratorCache =