diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index f1db475739a9..61a123d6ecc0 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -454,7 +454,7 @@ js::gc::GCRuntime::markRuntime(JSTracer *trc, if (!c->zone()->isCollecting()) c->markCrossCompartmentWrappers(trc); } - Debugger::markAllCrossCompartmentEdges(trc); + Debugger::markCrossCompartmentDebuggerObjectReferents(trc); } AutoGCRooter::traceAll(trc); diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 2f16ea2856a0..28d39562ebf5 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2662,7 +2662,7 @@ GCRuntime::updatePointersToRelocatedCells() // Mark roots to update them. markRuntime(&trc, MarkRuntime); Debugger::markAll(&trc); - Debugger::markAllCrossCompartmentEdges(&trc); + Debugger::markCrossCompartmentDebuggerObjectReferents(&trc); for (GCCompartmentsIter c(rt); !c.done(); c.next()) { WeakMapBase::markAll(c, &trc); diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 86cc074de7a0..9a62ec31faba 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -93,11 +93,6 @@ enum { JSSLOT_DEBUGSOURCE_COUNT }; -static void DebuggerObject_trace(JSTracer *trc, JSObject *obj); -static void DebuggerEnv_trace(JSTracer *trc, JSObject *obj); -static void DebuggerScript_trace(JSTracer *trc, JSObject *obj); -static void DebuggerSource_trace(JSTracer *trc, JSObject *obj); - /*** Utils ***************************************************************************************/ @@ -2078,12 +2073,17 @@ Debugger::setObservesAllExecution(JSContext *cx, IsObserving observing) /*** Debugger JSObjects **************************************************************************/ void -Debugger::markCrossCompartmentEdges(JSTracer *trc) +Debugger::markKeysInCompartment(JSTracer *trc) { - objects.markCrossCompartmentEdges(trc); - environments.markCrossCompartmentEdges(trc); - scripts.markCrossCompartmentEdges(trc); - sources.markCrossCompartmentEdges(trc); + /* + * WeakMap::Range is deliberately private, to discourage C++ code from + * enumerating WeakMap keys. However in this case we need access, so we + * make a base-class reference. Range is public in HashMap. + */ + objects.markKeys(trc); + environments.markKeys(trc); + scripts.markKeys(trc); + sources.markKeys(trc); } /* @@ -2091,30 +2091,35 @@ Debugger::markCrossCompartmentEdges(JSTracer *trc) * discovered that the WeakMap was live; that is, some object containing the * WeakMap was marked during mark phase. * - * However, during zone GC, we have to do something about cross-compartment - * edges in non-GC'd compartments. Since the source may be live, we - * conservatively assume it is and mark the edge. + * However, during compartment GC, we have to do something about + * cross-compartment WeakMaps in non-GC'd compartments. If their keys and values + * might need to be marked, we have to do it manually. * - * Each Debugger object keeps four cross-compartment WeakMaps: objects, scripts, - * script source objects, and environments. They have the property that all - * their values are in the same compartment as the Debugger object, but we have - * to mark the keys and the private pointer in the wrapper object. + * Each Debugger object keeps found cross-compartment WeakMaps: objects, scripts, + * script source objects, and environments. They have the nice property that all + * their values are in the same compartment as the Debugger object, so we only + * need to mark the keys. We must simply mark all keys that are in a compartment + * being GC'd. * - * We must scan all Debugger objects regardless of whether they *currently* have - * any debuggees in a compartment being GC'd, because the WeakMap entries - * persist even when debuggees are removed. + * We must scan all Debugger objects regardless of whether they *currently* + * have any debuggees in a compartment being GC'd, because the WeakMap + * entries persist even when debuggees are removed. * * This happens during the initial mark phase, not iterative marking, because * all the edges being reported here are strong references. */ /* static */ void -Debugger::markAllCrossCompartmentEdges(JSTracer *trc) +Debugger::markCrossCompartmentDebuggerObjectReferents(JSTracer *trc) { JSRuntime *rt = trc->runtime(); + /* + * Mark all objects in comp that are referents of Debugger.Objects in other + * compartments. + */ for (Debugger *dbg = rt->debuggerList.getFirst(); dbg; dbg = dbg->getNext()) { if (!dbg->object->zone()->isCollecting()) - dbg->markCrossCompartmentEdges(trc); + dbg->markKeysInCompartment(trc); } } @@ -2208,6 +2213,7 @@ Debugger::markAll(JSTracer *trc) GlobalObjectSet &debuggees = dbg->debuggees; for (GlobalObjectSet::Enum e(debuggees); !e.empty(); e.popFront()) { GlobalObject *global = e.front(); + MarkObjectUnbarriered(trc, &global, "Global Object"); if (global != e.front()) e.rekeyFront(global); diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index 7748fa0b8241..04ef22ce4305 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -36,9 +36,10 @@ class Breakpoint; class DebuggerMemory; /* - * A weakmap from GC thing keys to JSObject values that supports the keys being - * in different compartments to the values. All values must be in the same - * compartment. + * A weakmap that supports the keys being in different compartments to the + * values, although all values must be in the same compartment. + * + * The Key and Value classes must support the compartment() method. * * The purpose of this is to allow the garbage collector to easily find edges * from debugee object compartments to debugger compartments when calculating @@ -54,13 +55,10 @@ class DebuggerMemory; * debugger compartments. If it is false, we assert that such entries are never * created. */ -template -class DebuggerWeakMap : private WeakMap, RelocatablePtrObject> +template +class DebuggerWeakMap : private WeakMap > { private: - typedef PreBarriered Key; - typedef RelocatablePtrObject Value; - typedef HashMap, @@ -114,10 +112,8 @@ class DebuggerWeakMap : private WeakMap, Relocatabl } public: - template - void markCrossCompartmentEdges(JSTracer *tracer) { + void markKeys(JSTracer *tracer) { for (Enum e(*static_cast(this)); !e.empty(); e.popFront()) { - traceValueEdges(tracer, e.front().value()); Key key = e.front().key(); gc::Mark(tracer, &key, "Debugger WeakMap key"); if (key != e.front().key()) @@ -286,15 +282,15 @@ class Debugger : private mozilla::LinkedListElement FrameMap frames; /* An ephemeral map from JSScript* to Debugger.Script instances. */ - typedef DebuggerWeakMap ScriptWeakMap; + typedef DebuggerWeakMap ScriptWeakMap; ScriptWeakMap scripts; /* The map from debuggee source script objects to their Debugger.Source instances. */ - typedef DebuggerWeakMap SourceWeakMap; + typedef DebuggerWeakMap SourceWeakMap; SourceWeakMap sources; /* The map from debuggee objects to their Debugger.Object instances. */ - typedef DebuggerWeakMap ObjectWeakMap; + typedef DebuggerWeakMap ObjectWeakMap; ObjectWeakMap objects; /* The map from debuggee Envs to Debugger.Environment instances. */ @@ -360,7 +356,7 @@ class Debugger : private mozilla::LinkedListElement static void traceObject(JSTracer *trc, JSObject *obj); void trace(JSTracer *trc); static void finalize(FreeOp *fop, JSObject *obj); - void markCrossCompartmentEdges(JSTracer *tracer); + void markKeysInCompartment(JSTracer *tracer); static const Class jsclass; @@ -510,7 +506,7 @@ class Debugger : private mozilla::LinkedListElement * Debugger objects that are definitely live but not yet marked, it marks * them and returns true. If not, it returns false. */ - static void markAllCrossCompartmentEdges(JSTracer *tracer); + static void markCrossCompartmentDebuggerObjectReferents(JSTracer *tracer); static bool markAllIteratively(GCMarker *trc); static void markAll(JSTracer *trc); static void sweepAll(FreeOp *fop);