mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Use WeakMap for the Debug::objects, the mapping from referents to Debug.Objects. r=jorendorff, push=jorendorff.
This commit is contained in:
parent
fcfd80cfc5
commit
f79cb0d6c7
@ -150,7 +150,7 @@ enum {
|
||||
|
||||
Debug::Debug(JSObject *dbg, JSObject *hooks)
|
||||
: object(dbg), hooksObject(hooks), uncaughtExceptionHook(NULL), enabled(true),
|
||||
hasDebuggerHandler(false), hasThrowHandler(false)
|
||||
hasDebuggerHandler(false), hasThrowHandler(false), objects(dbg->compartment()->rt)
|
||||
{
|
||||
// This always happens within a request on some cx.
|
||||
JSRuntime *rt = dbg->compartment()->rt;
|
||||
@ -259,7 +259,7 @@ Debug::wrapDebuggeeValue(JSContext *cx, Value *vp)
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjectMap::AddPtr p = objects.lookupForAdd(ccwobj);
|
||||
ObjectWeakMap::AddPtr p = objects.lookupForAdd(ccwobj);
|
||||
if (p) {
|
||||
vp->setObject(*p->value);
|
||||
} else {
|
||||
@ -560,36 +560,6 @@ Debug::mark(GCMarker *trc, JSCompartment *comp, JSGCInvocationKind gckind)
|
||||
markedAny = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Handling Debug.Objects:
|
||||
//
|
||||
// If obj (the Debug object) hasn't been marked
|
||||
// yet, it may not be live, so don't mark anything.
|
||||
//
|
||||
// If comp is the debuggee's compartment, do nothing. No
|
||||
// referent objects will be collected, since we have a
|
||||
// wrapper of each one.
|
||||
//
|
||||
// If comp is the debugger's compartment, mark all
|
||||
// Debug.Objects, since the referents might be alive and
|
||||
// therefore the table entries must remain.
|
||||
//
|
||||
// If comp is null, then for each key (referent-wrapper)
|
||||
// that is marked, mark the corresponding value.
|
||||
//
|
||||
if (obj->isMarked() && (!comp || obj->compartment() == comp)) {
|
||||
for (ObjectMap::Range r = dbg->objects.all(); !r.empty(); r.popFront()) {
|
||||
// The unwrap() call below has the following effect: we
|
||||
// mark the Debug.Object if the *referent* is alive,
|
||||
// even if the CCW of the referent seems unreachable.
|
||||
if (!r.front().value->isMarked() &&
|
||||
(comp || r.front().key->unwrap()->isMarked())) {
|
||||
MarkObject(trc, *r.front().value,
|
||||
"Debug.Object with live referent");
|
||||
markedAny = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -598,21 +568,29 @@ Debug::mark(GCMarker *trc, JSCompartment *comp, JSGCInvocationKind gckind)
|
||||
}
|
||||
|
||||
void
|
||||
Debug::trace(JSTracer *trc, JSObject *obj)
|
||||
Debug::traceObject(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
if (Debug *dbg = (Debug *) obj->getPrivate()) {
|
||||
MarkObject(trc, *dbg->hooksObject, "hooks");
|
||||
if (dbg->uncaughtExceptionHook)
|
||||
MarkObject(trc, *dbg->uncaughtExceptionHook, "hooks");
|
||||
if (Debug *dbg = Debug::fromJSObject(obj))
|
||||
dbg->trace(trc);
|
||||
}
|
||||
|
||||
// Mark Debug.Frame objects that are reachable from JS if we look them up
|
||||
// again (because the corresponding StackFrame is still on the stack).
|
||||
for (FrameMap::Enum e(dbg->frames); !e.empty(); e.popFront()) {
|
||||
JSObject *frameobj = e.front().value;
|
||||
JS_ASSERT(frameobj->getPrivate());
|
||||
MarkObject(trc, *frameobj, "live Debug.Frame");
|
||||
}
|
||||
void
|
||||
Debug::trace(JSTracer *trc)
|
||||
{
|
||||
MarkObject(trc, *hooksObject, "hooks");
|
||||
if (uncaughtExceptionHook)
|
||||
MarkObject(trc, *uncaughtExceptionHook, "hooks");
|
||||
|
||||
// Mark Debug.Frame objects that are reachable from JS if we look them up
|
||||
// again (because the corresponding StackFrame is still on the stack).
|
||||
for (FrameMap::Enum e(frames); !e.empty(); e.popFront()) {
|
||||
JSObject *frameobj = e.front().value;
|
||||
JS_ASSERT(frameobj->getPrivate());
|
||||
MarkObject(trc, *frameobj, "live Debug.Frame");
|
||||
}
|
||||
|
||||
// Trace the referent -> Debug.Object weak map.
|
||||
objects.trace(trc);
|
||||
}
|
||||
|
||||
void
|
||||
@ -621,14 +599,7 @@ Debug::sweepAll(JSRuntime *rt)
|
||||
for (JSCList *p = &rt->debuggerList; (p = JS_NEXT_LINK(p)) != &rt->debuggerList;) {
|
||||
Debug *dbg = (Debug *) ((unsigned char *) p - offsetof(Debug, link));
|
||||
|
||||
if (dbg->object->isMarked()) {
|
||||
// Sweep ObjectMap entries for referents being collected.
|
||||
for (ObjectMap::Enum e(dbg->objects); !e.empty(); e.popFront()) {
|
||||
JS_ASSERT(e.front().key->isMarked() == e.front().value->isMarked());
|
||||
if (!e.front().value->isMarked())
|
||||
e.removeFront();
|
||||
}
|
||||
} else {
|
||||
if (!dbg->object->isMarked()) {
|
||||
// If this Debug is being GC'd, detach it from its debuggees. In the case of
|
||||
// runtime-wide GC, the debuggee might be GC'd too. Since detaching requires
|
||||
// access to both objects, this must be done before finalize time. However, in
|
||||
@ -690,7 +661,7 @@ Class Debug::jsclass = {
|
||||
NULL, /* construct */
|
||||
NULL, /* xdrObject */
|
||||
NULL, /* hasInstance */
|
||||
Debug::trace
|
||||
Debug::traceObject
|
||||
};
|
||||
|
||||
JSBool
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "jscompartment.h"
|
||||
#include "jsgc.h"
|
||||
#include "jshashtable.h"
|
||||
#include "jsweakmap.h"
|
||||
#include "jswrapper.h"
|
||||
#include "jsvalue.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
@ -75,12 +76,28 @@ class Debug {
|
||||
FrameMap;
|
||||
FrameMap frames;
|
||||
|
||||
// Mark policy for ObjectMap.
|
||||
class ObjectMapMarkPolicy: public DefaultMarkPolicy<JSObject *, JSObject *> {
|
||||
typedef DefaultMarkPolicy<JSObject *, JSObject *> Base;
|
||||
public:
|
||||
explicit ObjectMapMarkPolicy(JSTracer *tracer) : Base(tracer) { }
|
||||
|
||||
// The unwrap() call has the following effect: we mark the Debug.Object if the
|
||||
// *referent* is alive, even if the CCW of the referent seems unreachable. Since
|
||||
// the value always refers to the CCW, marking the value marks the CCW, so we
|
||||
// needn't worry that the CCW will go dead.
|
||||
bool keyMarked(JSObject *k) { return k->unwrap()->isMarked(); }
|
||||
void markKey(JSObject *k, const char *description) {
|
||||
js::gc::MarkObject(tracer, *k->unwrap(), description);
|
||||
}
|
||||
};
|
||||
|
||||
// Keys are referents, values are Debug.Object objects. The combination of
|
||||
// the a key being live and this Debug being live keeps the corresponding
|
||||
// Debug.Object alive.
|
||||
typedef HashMap<JSObject *, JSObject *, DefaultHasher<JSObject *>, SystemAllocPolicy>
|
||||
ObjectMap;
|
||||
ObjectMap objects;
|
||||
typedef WeakMap<JSObject *, JSObject *, DefaultHasher<JSObject *>, ObjectMapMarkPolicy>
|
||||
ObjectWeakMap;
|
||||
ObjectWeakMap objects;
|
||||
|
||||
bool addDebuggeeGlobal(JSContext *cx, GlobalObject *obj);
|
||||
void removeDebuggeeGlobal(GlobalObject *global, GlobalObjectSet::Enum *compartmentEnum,
|
||||
@ -91,7 +108,8 @@ class Debug {
|
||||
bool callHook = true);
|
||||
JSObject *unwrapDebuggeeArgument(JSContext *cx, Value *vp);
|
||||
|
||||
static void trace(JSTracer *trc, JSObject *obj);
|
||||
static void traceObject(JSTracer *trc, JSObject *obj);
|
||||
void trace(JSTracer *trc);
|
||||
static void finalize(JSContext *cx, JSObject *obj);
|
||||
|
||||
static Class jsclass;
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "jsapi.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsobj.h"
|
||||
#include "jsgcmark.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
@ -158,7 +159,8 @@ class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>, publ
|
||||
typedef typename Base::Enum Enum;
|
||||
|
||||
public:
|
||||
WeakMap(JSContext *cx) : Base(cx) { }
|
||||
explicit WeakMap(JSRuntime *rt) : Base(rt) { }
|
||||
explicit WeakMap(JSContext *cx) : Base(cx) { }
|
||||
|
||||
private:
|
||||
void nonMarkingTrace(JSTracer *tracer) {
|
||||
@ -199,7 +201,6 @@ class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>, publ
|
||||
}
|
||||
};
|
||||
|
||||
// Marking policy for maps from JSObject pointers to js::Values.
|
||||
template <>
|
||||
class DefaultMarkPolicy<JSObject *, Value> {
|
||||
private:
|
||||
@ -220,6 +221,22 @@ class DefaultMarkPolicy<JSObject *, Value> {
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class DefaultMarkPolicy<JSObject *, JSObject *> {
|
||||
public:
|
||||
DefaultMarkPolicy(JSTracer *t) : tracer(t) { }
|
||||
bool keyMarked(JSObject *k) { return !IsAboutToBeFinalized(tracer->context, k); }
|
||||
bool valueMarked(JSObject *v) { return !IsAboutToBeFinalized(tracer->context, v); }
|
||||
void markKey(JSObject *k, const char *description) {
|
||||
js::gc::MarkObject(tracer, *k, description);
|
||||
}
|
||||
void markValue(JSObject *v, const char *description) {
|
||||
js::gc::MarkObject(tracer, *v, description);
|
||||
}
|
||||
protected:
|
||||
JSTracer *tracer;
|
||||
};
|
||||
|
||||
// The class of JavaScript WeakMap objects.
|
||||
extern Class WeakMapClass;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user