зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1571021 - Key wrapper maps by wrapped type directly and remove CrossCompartmentKey class r=jandem?
Differential Revision: https://phabricator.services.mozilla.com/D41184 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
a4a756e0e6
Коммит
3fb04aa631
|
@ -119,6 +119,7 @@ struct GCPointerPolicy {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
static bool isTenured(T v) { return !js::gc::IsInsideNursery(v); }
|
||||
static bool isValid(T v) { return js::gc::IsCellPointerValidOrNull(v); }
|
||||
};
|
||||
#define EXPAND_SPECIALIZE_GCPOLICY(Type) \
|
||||
|
|
|
@ -4614,7 +4614,7 @@ void GCRuntime::markCompartments() {
|
|||
while (!workList.empty()) {
|
||||
Compartment* comp = workList.popCopy();
|
||||
for (Compartment::ObjectWrapperEnum e(comp); !e.empty(); e.popFront()) {
|
||||
Compartment* dest = e.front().mutableKey().compartment();
|
||||
Compartment* dest = e.front().key()->compartment();
|
||||
if (dest && !dest->gcState.maybeAlive) {
|
||||
dest->gcState.maybeAlive = true;
|
||||
if (!workList.append(dest)) {
|
||||
|
@ -5014,10 +5014,7 @@ static void DropStringWrappers(JSRuntime* rt) {
|
|||
* compartment group.
|
||||
*/
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
for (Compartment::StringWrapperEnum e(c); !e.empty(); e.popFront()) {
|
||||
MOZ_ASSERT(e.front().key().is<JSString*>());
|
||||
e.removeFront();
|
||||
}
|
||||
c->dropStringWrappersOnGC();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5041,9 +5038,9 @@ static void DropStringWrappers(JSRuntime* rt) {
|
|||
bool Compartment::findSweepGroupEdges() {
|
||||
Zone* source = zone();
|
||||
for (ObjectWrapperEnum e(this); !e.empty(); e.popFront()) {
|
||||
CrossCompartmentKey& key = e.front().mutableKey();
|
||||
JSObject* key = e.front().mutableKey();
|
||||
|
||||
Zone* target = key.zone();
|
||||
Zone* target = key->zone();
|
||||
if (!target->isGCMarking()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -5052,7 +5049,7 @@ bool Compartment::findSweepGroupEdges() {
|
|||
// is not still being marked when we start sweeping the wrapped zone. As an
|
||||
// optimization, if the wrapped object is already marked black there is no
|
||||
// danger of later marking and we can skip this.
|
||||
if (key.as<JSObject*>()->asTenured().isMarkedBlack()) {
|
||||
if (key->asTenured().isMarkedBlack()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -174,6 +174,11 @@ class NurseryAwareHashMap {
|
|||
map.sweep();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
map.clear();
|
||||
nurseryEntries.clear();
|
||||
}
|
||||
|
||||
bool hasNurseryEntries() const { return !nurseryEntries.empty(); }
|
||||
};
|
||||
|
||||
|
|
|
@ -108,7 +108,7 @@ JS_PUBLIC_API void JS::TraceIncomingCCWs(
|
|||
continue;
|
||||
}
|
||||
for (Compartment::ObjectWrapperEnum e(comp); !e.empty(); e.popFront()) {
|
||||
JSObject* obj = e.front().key().as<JSObject*>();
|
||||
JSObject* obj = e.front().key();
|
||||
Compartment* comp = obj->compartment();
|
||||
if (compartments.has(comp)) {
|
||||
mozilla::DebugOnly<JSObject*> prior = obj;
|
||||
|
|
|
@ -537,11 +537,11 @@ JS_FRIEND_API void js::VisitGrayWrapperTargets(Zone* zone,
|
|||
void* closure) {
|
||||
for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
|
||||
for (Compartment::ObjectWrapperEnum e(comp); !e.empty(); e.popFront()) {
|
||||
e.front().mutableKey().applyToWrapped([callback, closure](auto tp) {
|
||||
if ((*tp)->isMarkedGray()) {
|
||||
callback(closure, JS::GCCellPtr(*tp));
|
||||
}
|
||||
});
|
||||
JSObject* target = e.front().key();
|
||||
if (target->isMarkedGray()) {
|
||||
JS::AutoSuppressGCAnalysis nogc;
|
||||
callback(closure, JS::GCCellPtr(target));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -436,9 +436,7 @@ JS_FRIEND_API bool js::NukeCrossCompartmentWrappers(
|
|||
target->compartment() == c.get() && NukedAllRealms(c.get()));
|
||||
|
||||
// Iterate only the wrappers that have target compartment matched unless
|
||||
// |nukeAll| is true. The string wrappers that we're not interested in
|
||||
// won't be iterated, we can exclude them easily because they have
|
||||
// compartment nullptr. Use Maybe to avoid copying from conditionally
|
||||
// |nukeAll| is true. Use Maybe to avoid copying from conditionally
|
||||
// initializing ObjectWrapperEnum.
|
||||
mozilla::Maybe<Compartment::ObjectWrapperEnum> e;
|
||||
if (MOZ_LIKELY(!nukeAll)) {
|
||||
|
@ -448,19 +446,13 @@ JS_FRIEND_API bool js::NukeCrossCompartmentWrappers(
|
|||
c.get()->nukedOutgoingWrappers = true;
|
||||
}
|
||||
for (; !e->empty(); e->popFront()) {
|
||||
// Skip debugger references because NukeCrossCompartmentWrapper()
|
||||
// doesn't know how to nuke them yet, see bug 1084626 for more
|
||||
// information.
|
||||
const CrossCompartmentKey& k = e->front().key();
|
||||
if (!k.is<JSObject*>()) {
|
||||
continue;
|
||||
}
|
||||
JSObject* key = e->front().key();
|
||||
|
||||
AutoWrapperRooter wobj(cx, WrapperValue(*e));
|
||||
|
||||
// Unwrap from the wrapped object in CrossCompartmentKey instead of
|
||||
// the wrapper, this could save us a bit of time.
|
||||
JSObject* wrapped = UncheckedUnwrap(k.as<JSObject*>());
|
||||
// Unwrap from the wrapped object in key instead of the wrapper, this
|
||||
// could save us a bit of time.
|
||||
JSObject* wrapped = UncheckedUnwrap(key);
|
||||
|
||||
// Don't nuke wrappers for objects in other realms in the target
|
||||
// compartment unless nukeAll is set because in that case we want to nuke
|
||||
|
@ -642,16 +634,10 @@ JS_FRIEND_API bool js::RecomputeWrappers(
|
|||
evictedNursery = true;
|
||||
}
|
||||
|
||||
// Iterate over the wrappers, filtering appropriately.
|
||||
// Iterate over object wrappers, filtering appropriately.
|
||||
for (Compartment::ObjectWrapperEnum e(c, targetFilter); !e.empty();
|
||||
e.popFront()) {
|
||||
// Filter out non-objects.
|
||||
CrossCompartmentKey& k = e.front().mutableKey();
|
||||
if (!k.is<JSObject*>()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add it to the list.
|
||||
// Add the wrapper to the list.
|
||||
if (!toRecompute.append(WrapperValue(e))) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -54,13 +54,11 @@ static inline void CheckWrapperMapEntry(const Map& map, Entry& entry) {
|
|||
* wrapperMap that points into the nursery, and that the hash table entries
|
||||
* are discoverable.
|
||||
*/
|
||||
auto& key = entry.front().mutableKey();
|
||||
key.applyToWrapped([&](auto tp) {
|
||||
CheckGCThingAfterMovingGC(*tp);
|
||||
auto key = entry.front().key();
|
||||
CheckGCThingAfterMovingGC(key);
|
||||
|
||||
auto ptr = map.lookup(CrossCompartmentKey(*tp));
|
||||
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &entry.front());
|
||||
});
|
||||
auto ptr = map.lookup(key);
|
||||
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &entry.front());
|
||||
}
|
||||
|
||||
void Compartment::checkWrapperMapAfterMovingGC() {
|
||||
|
@ -74,10 +72,8 @@ void Compartment::checkWrapperMapAfterMovingGC() {
|
|||
|
||||
#endif // JSGC_HASH_TABLE_CHECKS
|
||||
|
||||
bool Compartment::putWrapper(JSContext* cx, JSObject* obj,
|
||||
bool Compartment::putWrapper(JSContext* cx, JSObject* wrapped,
|
||||
const js::Value& wrapper) {
|
||||
CrossCompartmentKey wrapped(obj);
|
||||
MOZ_ASSERT(wrapper.isObject());
|
||||
MOZ_ASSERT(!js::IsProxy(&wrapper.toObject()) ||
|
||||
js::GetProxyHandler(&wrapper.toObject())->family() !=
|
||||
js::GetDOMRemoteProxyHandlerFamily());
|
||||
|
@ -90,11 +86,8 @@ bool Compartment::putWrapper(JSContext* cx, JSObject* obj,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Compartment::putWrapper(JSContext* cx, JSString* str,
|
||||
bool Compartment::putWrapper(JSContext* cx, JSString* wrapped,
|
||||
const js::Value& wrapper) {
|
||||
CrossCompartmentKey wrapped(str);
|
||||
MOZ_ASSERT(wrapper.isString());
|
||||
|
||||
if (!crossCompartmentStringWrappers.put(wrapped, wrapper)) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
|
@ -443,16 +436,14 @@ void Compartment::traceOutgoingCrossCompartmentWrappers(JSTracer* trc) {
|
|||
trc->runtime()->gc.isHeapCompacting());
|
||||
|
||||
for (ObjectWrapperEnum e(this); !e.empty(); e.popFront()) {
|
||||
if (e.front().key().is<JSObject*>()) {
|
||||
Value v = e.front().value().unbarrieredGet();
|
||||
ProxyObject* wrapper = &v.toObject().as<ProxyObject>();
|
||||
Value v = e.front().value().unbarrieredGet();
|
||||
ProxyObject* wrapper = &v.toObject().as<ProxyObject>();
|
||||
|
||||
/*
|
||||
* We have a cross-compartment wrapper. Its private pointer may
|
||||
* point into the compartment being collected, so we should mark it.
|
||||
*/
|
||||
ProxyObject::traceEdgeToTarget(trc, wrapper);
|
||||
}
|
||||
/*
|
||||
* We have a cross-compartment wrapper. Its private pointer may
|
||||
* point into the compartment being collected, so we should mark it.
|
||||
*/
|
||||
ProxyObject::traceEdgeToTarget(trc, wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -469,6 +460,11 @@ void Compartment::traceIncomingCrossCompartmentEdgesForZoneGC(JSTracer* trc) {
|
|||
DebugAPI::traceCrossCompartmentEdges(trc);
|
||||
}
|
||||
|
||||
void Compartment::dropStringWrappersOnGC() {
|
||||
MOZ_ASSERT(JS::RuntimeHeapIsCollecting());
|
||||
crossCompartmentStringWrappers.clear();
|
||||
}
|
||||
|
||||
void Compartment::sweepAfterMinorGC(JSTracer* trc) {
|
||||
crossCompartmentObjectWrappers.sweepAfterMinorGC(trc);
|
||||
crossCompartmentStringWrappers.sweepAfterMinorGC(trc);
|
||||
|
@ -488,16 +484,6 @@ void Compartment::sweepCrossCompartmentWrappers() {
|
|||
crossCompartmentStringWrappers.sweep();
|
||||
}
|
||||
|
||||
void CrossCompartmentKey::trace(JSTracer* trc) {
|
||||
applyToWrapped(
|
||||
[trc](auto tp) { TraceRoot(trc, tp, "CrossCompartmentKey::wrapped"); });
|
||||
}
|
||||
|
||||
bool CrossCompartmentKey::needsSweep() {
|
||||
auto needsSweep = [](auto tp) { return IsAboutToBeFinalizedUnbarriered(tp); };
|
||||
return applyToWrapped(needsSweep);
|
||||
}
|
||||
|
||||
/* static */
|
||||
void Compartment::fixupCrossCompartmentWrappersAfterMovingGC(JSTracer* trc) {
|
||||
MOZ_ASSERT(trc->runtime()->gc.isHeapCompacting());
|
||||
|
|
|
@ -25,103 +25,6 @@
|
|||
|
||||
namespace js {
|
||||
|
||||
// A key in a WrapperMap, a compartment's map from entities in other
|
||||
// compartments to the wrapper objects the compartment's own code must use to
|
||||
// refer to them.
|
||||
//
|
||||
// All cross-compartment edges must be represented either in the source
|
||||
// compartment's wrapper map or in one of the debugger weakmaps.
|
||||
//
|
||||
// WrapperMaps have a complex key type because, in addition to mapping JSObjects
|
||||
// to their cross-compartment wrappers, they must also map non-atomized
|
||||
// JSStrings to their copies in the local compartment.
|
||||
class CrossCompartmentKey {
|
||||
public:
|
||||
using WrappedType = mozilla::Variant<JSObject*, JSString*>;
|
||||
|
||||
explicit CrossCompartmentKey(JSObject* obj) : wrapped(obj) {
|
||||
MOZ_RELEASE_ASSERT(obj);
|
||||
}
|
||||
explicit CrossCompartmentKey(JSString* str) : wrapped(str) {
|
||||
MOZ_RELEASE_ASSERT(str);
|
||||
}
|
||||
explicit CrossCompartmentKey(const JS::Value& v)
|
||||
: wrapped(v.isString() ? WrappedType(v.toString())
|
||||
: WrappedType(&v.toObject())) {}
|
||||
|
||||
bool operator==(const CrossCompartmentKey& other) const {
|
||||
return wrapped == other.wrapped;
|
||||
}
|
||||
bool operator!=(const CrossCompartmentKey& other) const {
|
||||
return wrapped != other.wrapped;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool is() const {
|
||||
return wrapped.is<T>();
|
||||
}
|
||||
template <typename T>
|
||||
const T& as() const {
|
||||
return wrapped.as<T>();
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename F>
|
||||
struct ApplyToWrappedMatcher {
|
||||
F f_;
|
||||
explicit ApplyToWrappedMatcher(F f) : f_(f) {}
|
||||
auto operator()(JSObject*& obj) { return f_(&obj); }
|
||||
auto operator()(JSString*& str) { return f_(&str); }
|
||||
};
|
||||
|
||||
public:
|
||||
template <typename F>
|
||||
auto applyToWrapped(F f) {
|
||||
return wrapped.match(ApplyToWrappedMatcher<F>(f));
|
||||
}
|
||||
|
||||
JS::Compartment* compartment() {
|
||||
return applyToWrapped([](auto tp) { return (*tp)->maybeCompartment(); });
|
||||
}
|
||||
|
||||
JS::Zone* zone() {
|
||||
return applyToWrapped([](auto tp) { return (*tp)->zone(); });
|
||||
}
|
||||
|
||||
struct Hasher : public DefaultHasher<CrossCompartmentKey> {
|
||||
struct HashFunctor {
|
||||
HashNumber operator()(JSObject* obj) {
|
||||
return DefaultHasher<JSObject*>::hash(obj);
|
||||
}
|
||||
HashNumber operator()(JSString* str) {
|
||||
return DefaultHasher<JSString*>::hash(str);
|
||||
}
|
||||
};
|
||||
static HashNumber hash(const CrossCompartmentKey& key) {
|
||||
return key.wrapped.addTagToHash(key.wrapped.match(HashFunctor()));
|
||||
}
|
||||
|
||||
static bool match(const CrossCompartmentKey& l,
|
||||
const CrossCompartmentKey& k) {
|
||||
return l.wrapped == k.wrapped;
|
||||
}
|
||||
};
|
||||
|
||||
bool isTenured() const {
|
||||
auto self = const_cast<CrossCompartmentKey*>(this);
|
||||
return self->applyToWrapped([](auto tp) { return (*tp)->isTenured(); });
|
||||
}
|
||||
|
||||
void trace(JSTracer* trc);
|
||||
bool needsSweep();
|
||||
|
||||
private:
|
||||
CrossCompartmentKey() = delete;
|
||||
explicit CrossCompartmentKey(WrappedType&& wrapped)
|
||||
: wrapped(std::move(wrapped)) {}
|
||||
WrappedType wrapped;
|
||||
};
|
||||
|
||||
// The data structure for storing JSObject CCWs, which has a map per target
|
||||
// compartment so we can access them easily. String CCWs are stored in a
|
||||
// separate map.
|
||||
|
@ -129,8 +32,8 @@ class ObjectWrapperMap {
|
|||
static const size_t InitialInnerMapSize = 4;
|
||||
|
||||
using InnerMap =
|
||||
NurseryAwareHashMap<CrossCompartmentKey, JS::Value,
|
||||
CrossCompartmentKey::Hasher, ZoneAllocPolicy>;
|
||||
NurseryAwareHashMap<JSObject*, JS::Value, DefaultHasher<JSObject*>,
|
||||
ZoneAllocPolicy>;
|
||||
using OuterMap = GCHashMap<JS::Compartment*, InnerMap,
|
||||
DefaultHasher<JS::Compartment*>, ZoneAllocPolicy>;
|
||||
|
||||
|
@ -239,11 +142,10 @@ class ObjectWrapperMap {
|
|||
return true;
|
||||
}
|
||||
|
||||
Ptr lookup(const CrossCompartmentKey& k) const {
|
||||
MOZ_ASSERT(k.is<JSObject*>());
|
||||
auto op = map.lookup(const_cast<CrossCompartmentKey&>(k).compartment());
|
||||
Ptr lookup(JSObject* obj) const {
|
||||
auto op = map.lookup(obj->compartment());
|
||||
if (op) {
|
||||
auto ip = op->value().lookup(k);
|
||||
auto ip = op->value().lookup(obj);
|
||||
if (ip) {
|
||||
return Ptr(ip, op->value());
|
||||
}
|
||||
|
@ -257,10 +159,8 @@ class ObjectWrapperMap {
|
|||
}
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool put(const CrossCompartmentKey& k, const JS::Value& v) {
|
||||
MOZ_ASSERT(k.is<JSObject*>());
|
||||
JS::Compartment* c = const_cast<CrossCompartmentKey&>(k).compartment();
|
||||
MOZ_ASSERT(c);
|
||||
MOZ_MUST_USE bool put(JSObject* obj, const JS::Value& v) {
|
||||
JS::Compartment* c = obj->compartment();
|
||||
auto p = map.lookupForAdd(c);
|
||||
if (!p) {
|
||||
InnerMap m(zone, InitialInnerMapSize);
|
||||
|
@ -268,7 +168,7 @@ class ObjectWrapperMap {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
return p->value().put(k, v);
|
||||
return p->value().put(obj, v);
|
||||
}
|
||||
|
||||
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
|
||||
|
@ -322,9 +222,8 @@ class ObjectWrapperMap {
|
|||
};
|
||||
|
||||
using StringWrapperMap =
|
||||
js::NurseryAwareHashMap<js::CrossCompartmentKey, JS::Value,
|
||||
js::CrossCompartmentKey::Hasher,
|
||||
js::ZoneAllocPolicy>;
|
||||
NurseryAwareHashMap<JSString*, JS::Value, DefaultHasher<JSString*>,
|
||||
ZoneAllocPolicy>;
|
||||
|
||||
} // namespace js
|
||||
|
||||
|
@ -448,11 +347,11 @@ class JS::Compartment {
|
|||
const js::Value& wrapper);
|
||||
|
||||
js::ObjectWrapperMap::Ptr lookupWrapper(JSObject* obj) const {
|
||||
return crossCompartmentObjectWrappers.lookup(js::CrossCompartmentKey(obj));
|
||||
return crossCompartmentObjectWrappers.lookup(obj);
|
||||
}
|
||||
|
||||
js::StringWrapperMap::Ptr lookupWrapper(JSString* str) const {
|
||||
return crossCompartmentStringWrappers.lookup(js::CrossCompartmentKey(str));
|
||||
return crossCompartmentStringWrappers.lookup(str);
|
||||
}
|
||||
|
||||
void removeWrapper(js::ObjectWrapperMap::Ptr p) {
|
||||
|
@ -489,6 +388,7 @@ class JS::Compartment {
|
|||
*/
|
||||
void traceOutgoingCrossCompartmentWrappers(JSTracer* trc);
|
||||
static void traceIncomingCrossCompartmentEdgesForZoneGC(JSTracer* trc);
|
||||
void dropStringWrappersOnGC();
|
||||
|
||||
void sweepRealms(js::FreeOp* fop, bool keepAtleastOne,
|
||||
bool destroyingRuntime);
|
||||
|
@ -597,14 +497,4 @@ class MOZ_RAII AutoWrapperRooter : private JS::AutoGCRooter {
|
|||
|
||||
} /* namespace js */
|
||||
|
||||
namespace JS {
|
||||
template <>
|
||||
struct GCPolicy<js::CrossCompartmentKey>
|
||||
: public StructGCPolicy<js::CrossCompartmentKey> {
|
||||
static bool isTenured(const js::CrossCompartmentKey& key) {
|
||||
return key.isTenured();
|
||||
}
|
||||
};
|
||||
} // namespace JS
|
||||
|
||||
#endif /* vm_Compartment_h */
|
||||
|
|
Загрузка…
Ссылка в новой задаче