зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1479388 - Move most WeakMap inline method definitions into a separate header r=sfink
This commit is contained in:
Родитель
8c1a2345bc
Коммит
e0ec59962b
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
#include "vm/ProxyObject.h"
|
#include "vm/ProxyObject.h"
|
||||||
|
|
||||||
|
#include "gc/WeakMap-inl.h"
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#define builtin_WeakMapObject_h
|
#define builtin_WeakMapObject_h
|
||||||
|
|
||||||
#include "gc/WeakMap.h"
|
#include "gc/WeakMap.h"
|
||||||
#include "vm/JSObject.h"
|
#include "vm/NativeObject.h"
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "ds/InlineTable.h"
|
#include "ds/InlineTable.h"
|
||||||
#include "frontend/ParseNode.h"
|
#include "frontend/ParseNode.h"
|
||||||
#include "frontend/TokenStream.h"
|
#include "frontend/TokenStream.h"
|
||||||
|
#include "gc/Zone.h"
|
||||||
#include "vm/BytecodeUtil.h"
|
#include "vm/BytecodeUtil.h"
|
||||||
#include "vm/EnvironmentObject.h"
|
#include "vm/EnvironmentObject.h"
|
||||||
#include "vm/JSAtom.h"
|
#include "vm/JSAtom.h"
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "gc/WeakMap.h"
|
#include "gc/WeakMap-inl.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
|
@ -8,20 +8,24 @@
|
||||||
#define gc_WeakMap_h
|
#define gc_WeakMap_h
|
||||||
|
|
||||||
#include "mozilla/LinkedList.h"
|
#include "mozilla/LinkedList.h"
|
||||||
#include "mozilla/Move.h"
|
|
||||||
|
|
||||||
#include "jsfriendapi.h"
|
|
||||||
|
|
||||||
|
#include "gc/Barrier.h"
|
||||||
#include "gc/DeletePolicy.h"
|
#include "gc/DeletePolicy.h"
|
||||||
#include "gc/StoreBuffer.h"
|
|
||||||
#include "js/HashTable.h"
|
#include "js/HashTable.h"
|
||||||
#include "vm/JSObject.h"
|
|
||||||
#include "vm/Realm.h"
|
namespace JS {
|
||||||
|
class Zone;
|
||||||
|
} // namespace JS
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
class GCMarker;
|
class GCMarker;
|
||||||
class WeakMapBase;
|
class WeakMapBase;
|
||||||
|
struct WeakMapTracer;
|
||||||
|
|
||||||
|
namespace gc {
|
||||||
|
struct WeakMarkable;
|
||||||
|
} // namespace gc
|
||||||
|
|
||||||
// A subclass template of js::HashMap whose keys and values may be garbage-collected. When
|
// A subclass template of js::HashMap whose keys and values may be garbage-collected. When
|
||||||
// a key is collected, the table entry disappears, dropping its reference to the value.
|
// a key is collected, the table entry disappears, dropping its reference to the value.
|
||||||
|
@ -49,7 +53,7 @@ class WeakMapBase : public mozilla::LinkedListElement<WeakMapBase>
|
||||||
WeakMapBase(JSObject* memOf, JS::Zone* zone);
|
WeakMapBase(JSObject* memOf, JS::Zone* zone);
|
||||||
virtual ~WeakMapBase();
|
virtual ~WeakMapBase();
|
||||||
|
|
||||||
Zone* zone() const { return zone_; }
|
JS::Zone* zone() const { return zone_; }
|
||||||
|
|
||||||
// Garbage collector entry points.
|
// Garbage collector entry points.
|
||||||
|
|
||||||
|
@ -107,17 +111,6 @@ class WeakMapBase : public mozilla::LinkedListElement<WeakMapBase>
|
||||||
bool marked;
|
bool marked;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static T extractUnbarriered(const WriteBarrieredBase<T>& v)
|
|
||||||
{
|
|
||||||
return v.get();
|
|
||||||
}
|
|
||||||
template <typename T>
|
|
||||||
static T* extractUnbarriered(T* v)
|
|
||||||
{
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Key, class Value,
|
template <class Key, class Value,
|
||||||
class HashPolicy = DefaultHasher<Key> >
|
class HashPolicy = DefaultHasher<Key> >
|
||||||
class WeakMap : public HashMap<Key, Value, HashPolicy, ZoneAllocPolicy>,
|
class WeakMap : public HashMap<Key, Value, HashPolicy, ZoneAllocPolicy>,
|
||||||
|
@ -132,16 +125,9 @@ class WeakMap : public HashMap<Key, Value, HashPolicy, ZoneAllocPolicy>,
|
||||||
typedef typename Base::Ptr Ptr;
|
typedef typename Base::Ptr Ptr;
|
||||||
typedef typename Base::AddPtr AddPtr;
|
typedef typename Base::AddPtr AddPtr;
|
||||||
|
|
||||||
explicit WeakMap(JSContext* cx, JSObject* memOf = nullptr)
|
explicit WeakMap(JSContext* cx, JSObject* memOf = nullptr);
|
||||||
: Base(cx->zone()), WeakMapBase(memOf, cx->zone()) { }
|
|
||||||
|
|
||||||
bool init(uint32_t len = 16) {
|
bool init(uint32_t len = 16);
|
||||||
if (!Base::init(len))
|
|
||||||
return false;
|
|
||||||
zone()->gcWeakMapList().insertFront(this);
|
|
||||||
marked = JS::IsIncrementalGCInProgress(TlsContext.get());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overwritten to add a read barrier to prevent an incorrectly gray value
|
// Overwritten to add a read barrier to prevent an incorrectly gray value
|
||||||
// from escaping the weak map. See the UnmarkGrayTracer::onChild comment in
|
// from escaping the weak map. See the UnmarkGrayTracer::onChild comment in
|
||||||
|
@ -170,204 +156,46 @@ class WeakMap : public HashMap<Key, Value, HashPolicy, ZoneAllocPolicy>,
|
||||||
// Resolve ambiguity with LinkedListElement<>::remove.
|
// Resolve ambiguity with LinkedListElement<>::remove.
|
||||||
using Base::remove;
|
using Base::remove;
|
||||||
|
|
||||||
// Trace a WeakMap entry based on 'markedCell' getting marked, where
|
void markEntry(GCMarker* marker, gc::Cell* markedCell, JS::GCCellPtr origKey) override;
|
||||||
// 'origKey' is the key in the weakmap. These will probably be the same,
|
|
||||||
// but can be different eg when markedCell is a delegate for origKey.
|
|
||||||
//
|
|
||||||
// This implementation does not use 'markedCell'; it looks up origKey and
|
|
||||||
// checks the mark bits on everything it cares about, one of which will be
|
|
||||||
// markedCell. But a subclass might use it to optimize the liveness check.
|
|
||||||
void markEntry(GCMarker* marker, gc::Cell* markedCell, JS::GCCellPtr origKey) override
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(marked);
|
|
||||||
|
|
||||||
// If this cast fails, then you're instantiating the WeakMap with a
|
void trace(JSTracer* trc) override;
|
||||||
// Lookup that can't be constructed from a Cell*. The WeakKeyTable
|
|
||||||
// mechanism is indexed with a GCCellPtr, so that won't work.
|
|
||||||
Ptr p = Base::lookup(static_cast<Lookup>(origKey.asCell()));
|
|
||||||
MOZ_ASSERT(p.found());
|
|
||||||
|
|
||||||
Key key(p->key());
|
|
||||||
MOZ_ASSERT((markedCell == extractUnbarriered(key)) || (markedCell == getDelegate(key)));
|
|
||||||
if (gc::IsMarked(marker->runtime(), &key)) {
|
|
||||||
TraceEdge(marker, &p->value(), "ephemeron value");
|
|
||||||
} else if (keyNeedsMark(key)) {
|
|
||||||
TraceEdge(marker, &p->value(), "WeakMap ephemeron value");
|
|
||||||
TraceEdge(marker, &key, "proxy-preserved WeakMap ephemeron key");
|
|
||||||
MOZ_ASSERT(key == p->key()); // No moving
|
|
||||||
}
|
|
||||||
key.unsafeSet(nullptr); // Prevent destructor from running barriers.
|
|
||||||
}
|
|
||||||
|
|
||||||
void trace(JSTracer* trc) override {
|
|
||||||
MOZ_ASSERT_IF(JS::RuntimeHeapIsBusy(), isInList());
|
|
||||||
|
|
||||||
TraceNullableEdge(trc, &memberOf, "WeakMap owner");
|
|
||||||
|
|
||||||
if (!Base::initialized())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (trc->isMarkingTracer()) {
|
|
||||||
MOZ_ASSERT(trc->weakMapAction() == ExpandWeakMaps);
|
|
||||||
marked = true;
|
|
||||||
(void) markIteratively(GCMarker::fromTracer(trc));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trc->weakMapAction() == DoNotTraceWeakMaps)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Trace keys only if weakMapAction() says to.
|
|
||||||
if (trc->weakMapAction() == TraceWeakMapKeysValues) {
|
|
||||||
for (Enum e(*this); !e.empty(); e.popFront())
|
|
||||||
TraceEdge(trc, &e.front().mutableKey(), "WeakMap entry key");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always trace all values (unless weakMapAction() is
|
|
||||||
// DoNotTraceWeakMaps).
|
|
||||||
for (Range r = Base::all(); !r.empty(); r.popFront())
|
|
||||||
TraceEdge(trc, &r.front().value(), "WeakMap entry value");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void addWeakEntry(GCMarker* marker, JS::GCCellPtr key, gc::WeakMarkable markable)
|
static void addWeakEntry(GCMarker* marker, JS::GCCellPtr key,
|
||||||
{
|
const gc::WeakMarkable& markable);
|
||||||
Zone* zone = key.asCell()->asTenured().zone();
|
|
||||||
|
|
||||||
auto p = zone->gcWeakKeys().get(key);
|
bool markIteratively(GCMarker* marker) override;
|
||||||
if (p) {
|
|
||||||
gc::WeakEntryVector& weakEntries = p->value;
|
|
||||||
if (!weakEntries.append(std::move(markable)))
|
|
||||||
marker->abortLinearWeakMarking();
|
|
||||||
} else {
|
|
||||||
gc::WeakEntryVector weakEntries;
|
|
||||||
MOZ_ALWAYS_TRUE(weakEntries.append(std::move(markable)));
|
|
||||||
if (!zone->gcWeakKeys().put(JS::GCCellPtr(key), std::move(weakEntries)))
|
|
||||||
marker->abortLinearWeakMarking();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool markIteratively(GCMarker* marker) override {
|
JSObject* getDelegate(JSObject* key) const;
|
||||||
MOZ_ASSERT(marked);
|
JSObject* getDelegate(JSScript* script) const;
|
||||||
|
JSObject* getDelegate(LazyScript* script) const;
|
||||||
bool markedAny = false;
|
|
||||||
|
|
||||||
for (Enum e(*this); !e.empty(); e.popFront()) {
|
|
||||||
// If the entry is live, ensure its key and value are marked.
|
|
||||||
bool keyIsMarked = gc::IsMarked(marker->runtime(), &e.front().mutableKey());
|
|
||||||
if (!keyIsMarked && keyNeedsMark(e.front().key())) {
|
|
||||||
TraceEdge(marker, &e.front().mutableKey(), "proxy-preserved WeakMap entry key");
|
|
||||||
keyIsMarked = true;
|
|
||||||
markedAny = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keyIsMarked) {
|
|
||||||
if (!gc::IsMarked(marker->runtime(), &e.front().value())) {
|
|
||||||
TraceEdge(marker, &e.front().value(), "WeakMap entry value");
|
|
||||||
markedAny = true;
|
|
||||||
}
|
|
||||||
} else if (marker->isWeakMarkingTracer()) {
|
|
||||||
// Entry is not yet known to be live. Record this weakmap and
|
|
||||||
// the lookup key in the list of weak keys. Also record the
|
|
||||||
// delegate, if any, because marking the delegate also marks
|
|
||||||
// the entry.
|
|
||||||
JS::GCCellPtr weakKey(extractUnbarriered(e.front().key()));
|
|
||||||
gc::WeakMarkable markable(this, weakKey);
|
|
||||||
addWeakEntry(marker, weakKey, markable);
|
|
||||||
if (JSObject* delegate = getDelegate(e.front().key()))
|
|
||||||
addWeakEntry(marker, JS::GCCellPtr(delegate), markable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return markedAny;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject* getDelegate(JSObject* key) const {
|
|
||||||
JSWeakmapKeyDelegateOp op = key->getClass()->extWeakmapKeyDelegateOp();
|
|
||||||
if (!op)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
JSObject* obj = op(key);
|
|
||||||
if (!obj)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
MOZ_ASSERT(obj->runtimeFromMainThread() == zone()->runtimeFromMainThread());
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject* getDelegate(JSScript* script) const {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
JSObject* getDelegate(LazyScript* script) const {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void exposeGCThingToActiveJS(const JS::Value& v) const { JS::ExposeValueToActiveJS(v); }
|
void exposeGCThingToActiveJS(const JS::Value& v) const { JS::ExposeValueToActiveJS(v); }
|
||||||
void exposeGCThingToActiveJS(JSObject* obj) const { JS::ExposeObjectToActiveJS(obj); }
|
void exposeGCThingToActiveJS(JSObject* obj) const { JS::ExposeObjectToActiveJS(obj); }
|
||||||
|
|
||||||
bool keyNeedsMark(JSObject* key) const {
|
bool keyNeedsMark(JSObject* key) const;
|
||||||
JSObject* delegate = getDelegate(key);
|
bool keyNeedsMark(JSScript* script) const;
|
||||||
/*
|
bool keyNeedsMark(LazyScript* script) const;
|
||||||
* Check if the delegate is marked with any color to properly handle
|
|
||||||
* gray marking when the key's delegate is black and the map is gray.
|
|
||||||
*/
|
|
||||||
return delegate && gc::IsMarkedUnbarriered(zone()->runtimeFromMainThread(), &delegate);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool keyNeedsMark(JSScript* script) const {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool keyNeedsMark(LazyScript* script) const {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool findZoneEdges() override {
|
bool findZoneEdges() override {
|
||||||
// This is overridden by ObjectValueMap.
|
// This is overridden by ObjectValueMap.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sweep() override {
|
void sweep() override;
|
||||||
/* Remove all entries whose keys remain unmarked. */
|
|
||||||
for (Enum e(*this); !e.empty(); e.popFront()) {
|
|
||||||
if (gc::IsAboutToBeFinalized(&e.front().mutableKey()))
|
|
||||||
e.removeFront();
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Once we've swept, all remaining edges should stay within the
|
|
||||||
* known-live part of the graph.
|
|
||||||
*/
|
|
||||||
assertEntriesNotAboutToBeFinalized();
|
|
||||||
}
|
|
||||||
|
|
||||||
void finish() override {
|
void finish() override {
|
||||||
Base::finish();
|
Base::finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* memberOf can be nullptr, which means that the map is not part of a JSObject. */
|
/* memberOf can be nullptr, which means that the map is not part of a JSObject. */
|
||||||
void traceMappings(WeakMapTracer* tracer) override {
|
void traceMappings(WeakMapTracer* tracer) override;
|
||||||
for (Range r = Base::all(); !r.empty(); r.popFront()) {
|
|
||||||
gc::Cell* key = gc::ToMarkable(r.front().key());
|
|
||||||
gc::Cell* value = gc::ToMarkable(r.front().value());
|
|
||||||
if (key && value) {
|
|
||||||
tracer->trace(memberOf,
|
|
||||||
JS::GCCellPtr(r.front().key().get()),
|
|
||||||
JS::GCCellPtr(r.front().value().get()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void assertEntriesNotAboutToBeFinalized() {
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
for (Range r = Base::all(); !r.empty(); r.popFront()) {
|
void assertEntriesNotAboutToBeFinalized();
|
||||||
Key k(r.front().key());
|
|
||||||
MOZ_ASSERT(!gc::IsAboutToBeFinalized(&k));
|
|
||||||
MOZ_ASSERT(!gc::IsAboutToBeFinalized(&r.front().value()));
|
|
||||||
MOZ_ASSERT(k == r.front().key());
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
#include "js/WeakMapPtr.h"
|
#include "js/WeakMapPtr.h"
|
||||||
|
|
||||||
#include "gc/WeakMap.h"
|
#include "gc/WeakMap-inl.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// Machinery for the externally-linkable JS::WeakMapPtr, which wraps js::WeakMap
|
// Machinery for the externally-linkable JS::WeakMapPtr, which wraps js::WeakMap
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "vm/Debugger.h"
|
#include "vm/Debugger.h"
|
||||||
|
|
||||||
|
#include "gc/WeakMap-inl.h"
|
||||||
#include "vm/Stack-inl.h"
|
#include "vm/Stack-inl.h"
|
||||||
|
|
||||||
/* static */ inline bool
|
/* static */ inline bool
|
||||||
|
|
|
@ -219,7 +219,9 @@ class DebuggerWeakMap : private WeakMap<HeapPtr<UnbarrieredKey>, HeapPtr<JSObjec
|
||||||
e.removeFront();
|
e.removeFront();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
Base::assertEntriesNotAboutToBeFinalized();
|
Base::assertEntriesNotAboutToBeFinalized();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_MUST_USE bool incZoneCount(JS::Zone* zone) {
|
MOZ_MUST_USE bool incZoneCount(JS::Zone* zone) {
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "vm/ArrayBufferObject.h"
|
#include "vm/ArrayBufferObject.h"
|
||||||
#include "vm/ErrorObject.h"
|
#include "vm/ErrorObject.h"
|
||||||
#include "vm/JSFunction.h"
|
#include "vm/JSFunction.h"
|
||||||
|
#include "vm/Realm.h"
|
||||||
#include "vm/RegExpStatics.h"
|
#include "vm/RegExpStatics.h"
|
||||||
#include "vm/Runtime.h"
|
#include "vm/Runtime.h"
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче