diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index 61a123d6ecc..f1db475739a 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::markCrossCompartmentDebuggerObjectReferents(trc); + Debugger::markAllCrossCompartmentEdges(trc); } AutoGCRooter::traceAll(trc); diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 5306d6c879a..697799749a1 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::markCrossCompartmentDebuggerObjectReferents(&trc); + Debugger::markAllCrossCompartmentEdges(&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 9a62ec31fab..86cc074de7a 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -93,6 +93,11 @@ 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 ***************************************************************************************/ @@ -2073,17 +2078,12 @@ Debugger::setObservesAllExecution(JSContext *cx, IsObserving observing) /*** Debugger JSObjects **************************************************************************/ void -Debugger::markKeysInCompartment(JSTracer *trc) +Debugger::markCrossCompartmentEdges(JSTracer *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); + objects.markCrossCompartmentEdges(trc); + environments.markCrossCompartmentEdges(trc); + scripts.markCrossCompartmentEdges(trc); + sources.markCrossCompartmentEdges(trc); } /* @@ -2091,35 +2091,30 @@ Debugger::markKeysInCompartment(JSTracer *trc) * discovered that the WeakMap was live; that is, some object containing the * WeakMap was marked during mark phase. * - * 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. + * 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. * - * 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. + * 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. * - * 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::markCrossCompartmentDebuggerObjectReferents(JSTracer *trc) +Debugger::markAllCrossCompartmentEdges(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->markKeysInCompartment(trc); + dbg->markCrossCompartmentEdges(trc); } } @@ -2213,7 +2208,6 @@ 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 04ef22ce430..7748fa0b824 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -36,10 +36,9 @@ class Breakpoint; class DebuggerMemory; /* - * 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. + * 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. * * The purpose of this is to allow the garbage collector to easily find edges * from debugee object compartments to debugger compartments when calculating @@ -55,10 +54,13 @@ class DebuggerMemory; * debugger compartments. If it is false, we assert that such entries are never * created. */ -template -class DebuggerWeakMap : private WeakMap > +template +class DebuggerWeakMap : private WeakMap, RelocatablePtrObject> { private: + typedef PreBarriered Key; + typedef RelocatablePtrObject Value; + typedef HashMap, @@ -112,8 +114,10 @@ class DebuggerWeakMap : private WeakMap > } public: - void markKeys(JSTracer *tracer) { + template + void markCrossCompartmentEdges(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()) @@ -282,15 +286,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. */ @@ -356,7 +360,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 markKeysInCompartment(JSTracer *tracer); + void markCrossCompartmentEdges(JSTracer *tracer); static const Class jsclass; @@ -506,7 +510,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 markCrossCompartmentDebuggerObjectReferents(JSTracer *tracer); + static void markAllCrossCompartmentEdges(JSTracer *tracer); static bool markAllIteratively(GCMarker *trc); static void markAll(JSTracer *trc); static void sweepAll(FreeOp *fop);