Bug 1102858 - Fix tracing of debugger objects' private pointers for compacting GC r=terrence

This commit is contained in:
Jon Coppeard 2014-12-01 06:07:25 -08:00
parent af7b548b52
commit 8f1b446425
4 changed files with 40 additions and 42 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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<DebuggerObject_trace>(trc);
environments.markCrossCompartmentEdges<DebuggerEnv_trace>(trc);
scripts.markCrossCompartmentEdges<DebuggerScript_trace>(trc);
sources.markCrossCompartmentEdges<DebuggerSource_trace>(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);

View File

@ -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 Key, class Value, bool InvisibleKeysOk=false>
class DebuggerWeakMap : private WeakMap<Key, Value, DefaultHasher<Key> >
template <class UnbarrieredKey, bool InvisibleKeysOk=false>
class DebuggerWeakMap : private WeakMap<PreBarriered<UnbarrieredKey>, RelocatablePtrObject>
{
private:
typedef PreBarriered<UnbarrieredKey> Key;
typedef RelocatablePtrObject Value;
typedef HashMap<JS::Zone *,
uintptr_t,
DefaultHasher<JS::Zone *>,
@ -112,8 +114,10 @@ class DebuggerWeakMap : private WeakMap<Key, Value, DefaultHasher<Key> >
}
public:
void markKeys(JSTracer *tracer) {
template <void (traceValueEdges)(JSTracer *, JSObject *)>
void markCrossCompartmentEdges(JSTracer *tracer) {
for (Enum e(*static_cast<Base *>(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<Debugger>
FrameMap frames;
/* An ephemeral map from JSScript* to Debugger.Script instances. */
typedef DebuggerWeakMap<PreBarrieredScript, RelocatablePtrObject> ScriptWeakMap;
typedef DebuggerWeakMap<JSScript*> ScriptWeakMap;
ScriptWeakMap scripts;
/* The map from debuggee source script objects to their Debugger.Source instances. */
typedef DebuggerWeakMap<PreBarrieredObject, RelocatablePtrObject, true> SourceWeakMap;
typedef DebuggerWeakMap<JSObject*, true> SourceWeakMap;
SourceWeakMap sources;
/* The map from debuggee objects to their Debugger.Object instances. */
typedef DebuggerWeakMap<PreBarrieredObject, RelocatablePtrObject> ObjectWeakMap;
typedef DebuggerWeakMap<JSObject*> ObjectWeakMap;
ObjectWeakMap objects;
/* The map from debuggee Envs to Debugger.Environment instances. */
@ -356,7 +360,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
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>
* 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);