| --- jsweakmap.h |
| +++ jsweakmap.h |
| @@ -78,17 +78,17 @@ class WeakMapBase { |
| |
| // Restore information about which weak maps are marked for many compartments. |
| static void restoreCompartmentMarkedWeakMaps(WeakMapSet& markedWeakMaps); |
| |
| // Remove a weakmap from its compartment's weakmaps list. |
| static void removeWeakMapFromList(WeakMapBase* weakmap); |
| |
| // Object keys must participate in ephemeron marking by overriding this method. |
| - virtual void maybeMarkEntry(JSTracer* trc, gc::Cell* l) = 0; |
| + virtual void maybeMarkEntry(JSTracer* trc, gc::Cell* markedCell, JS::GCCellPtr l) = 0; |
| |
| protected: |
| // Instance member functions called by the above. Instantiations of WeakMap override |
| // these with definitions appropriate for their Key and Value types. |
| virtual void nonMarkingTraceKeys(JSTracer* tracer) = 0; |
| virtual void nonMarkingTraceValues(JSTracer* tracer) = 0; |
| virtual bool markIteratively(JSTracer* tracer) = 0; |
| virtual void markEphemeronEntries(JSTracer* trc) = 0; |
| @@ -160,65 +160,76 @@ class WeakMap : public HashMap<Key, Valu |
| return p; |
| } |
| |
| // The WeakMap and some part of the key are marked. Mark the value if the |
| // key is "fully marked" according to the exact semantics of this WeakMap. |
| // (For a standard WeakMap, the key is either marked or not, so just mark |
| // the value here. But a subclass might have multipart keys with more |
| // complicated semantics.) |
| - virtual void maybeMarkEntry(JSTracer* trc, gc::Cell* l) |
| + virtual void maybeMarkEntry(JSTracer* trc, gc::Cell* markedCell, JS::GCCellPtr origKey) |
| { |
| MOZ_ASSERT(marked); |
| |
| + gc::Cell* l = origKey.asCell(); |
| Ptr p = Base::lookup(reinterpret_cast<const Lookup&>(l)); |
| Key key(p->key()); |
| - if (gc::IsMarked(&key)) |
| + if (gc::IsMarked(&key)) { |
| TraceEdge(trc, &p->value(), "ephemeron value"); |
| + } else if (keyNeedsMark(key)) { |
| + TraceEdge(trc, &p->value(), "WeakMap ephemeron value"); |
| + TraceEdge(trc, &key, "proxy-preserved WeakMap ephemeron key"); |
| + MOZ_ASSERT(key == p->key()); // No moving |
| + } |
| key.unsafeSet(nullptr); |
| } |
| |
| protected: |
| + static void addWeakEntry(JSTracer* trc, JS::GCCellPtr key, gc::WeakMarkable markable) |
| + { |
| + GCMarker& marker = *static_cast<GCMarker*>(trc); |
| + |
| + auto p = marker.weakKeys.get(key); |
| + if (p) { |
| + gc::WeakEntryVector& weakEntries = p->value; |
| + if (!weakEntries.append(Move(markable))) |
| + marker.abortLinearWeakMarking(); |
| + } else { |
| + gc::WeakEntryVector weakEntries; |
| + JS_ALWAYS_TRUE(weakEntries.append(Move(markable))); |
| + if (!marker.weakKeys.put(JS::GCCellPtr(key), Move(weakEntries))) |
| + marker.abortLinearWeakMarking(); |
| + } |
| + } |
| + |
| virtual void markEphemeronEntries(JSTracer* trc) { |
| - gc::WeakKeyTable& weakKeys = static_cast<GCMarker*>(trc)->weakKeys; |
| - |
| MOZ_ASSERT(marked); |
| for (Enum e(*this); !e.empty(); e.popFront()) { |
| Key key(e.front().key()); |
| |
| // If the entry is live, ensure its key and value are marked. |
| if (gc::IsMarked(&key)) { |
| (void) markValue(trc, &e.front().value()); |
| - if (e.front().key() != key) |
| - entryMoved(e, key); |
| + MOZ_ASSERT(key == e.front().key()); // No moving |
| } else if (keyNeedsMark(key)) { |
| TraceEdge(trc, &e.front().value(), "WeakMap entry value"); |
| TraceEdge(trc, &key, "proxy-preserved WeakMap entry key"); |
| - if (e.front().key() != key) |
| - entryMoved(e, key); |
| + MOZ_ASSERT(key == e.front().key()); // No moving |
| } else { |
| // Entry is not known to be live yet. Record it in the list of |
| - // weak keys. Or rather, record a pointer to this weakmap, so |
| - // we can look the key up again when we need to (to allow |
| - // incremental weak marking.) |
| - auto p = weakKeys.get(JS::GCCellPtr(key)); |
| - if (p) { |
| - gc::WeakEntryVector& weakEntries = p->value; |
| - if (!weakEntries.append(this)) { |
| - static_cast<GCMarker*>(trc)->endWeakMarkingPhase(); |
| - break; |
| - } |
| - } else { |
| - gc::WeakEntryVector weakEntries; |
| - JS_ALWAYS_TRUE(weakEntries.append(this)); |
| - if (!weakKeys.put(JS::GCCellPtr(key), Move(weakEntries))) { |
| - static_cast<GCMarker*>(trc)->endWeakMarkingPhase(); |
| - break; |
| - } |
| - } |
| + // weak keys. Or rather, record this weakmap and the lookup key |
| + // so we can repeat the lookup when we need to (to allow |
| + // incremental weak marking, we can't just store a pointer to |
| + // the entry.) Also record the delegate, if any, because |
| + // marking the delegate must also mark the entry. |
| + JS::GCCellPtr weakKey(key); |
| + gc::WeakMarkable markable(this, weakKey); |
| + addWeakEntry(trc, weakKey, markable); |
| + if (JSObject* delegate = getDelegate(key)) |
| + addWeakEntry(trc, JS::GCCellPtr(delegate), markable); |
| } |
| key.unsafeSet(nullptr); |
| } |
| } |
| |
| private: |
| void exposeGCThingToActiveJS(const JS::Value& v) const { JS::ExposeValueToActiveJS(v); } |
| void exposeGCThingToActiveJS(JSObject* obj) const { JS::ExposeObjectToActiveJS(obj); } |