зеркало из https://github.com/mozilla/gecko-dev.git
Bug 882162: Part 6 - Move the runtime and zone CC participants into mozilla::CycleCollectedJSRuntime. r=mccr8
This commit is contained in:
Родитель
cbe30a8739
Коммит
3faff59469
|
@ -2889,6 +2889,47 @@ XPCJSRuntime::OnJSContextNew(JSContext *cx)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
XPCJSRuntime::DescribeCustomObjects(JSObject* obj, js::Class* clasp,
|
||||||
|
char (&name)[72]) const
|
||||||
|
{
|
||||||
|
XPCNativeScriptableInfo *si = nullptr;
|
||||||
|
|
||||||
|
if (!IS_PROTO_CLASS(clasp)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
XPCWrappedNativeProto *p =
|
||||||
|
static_cast<XPCWrappedNativeProto*>(xpc_GetJSPrivate(obj));
|
||||||
|
si = p->GetScriptableInfo();
|
||||||
|
|
||||||
|
if (!si) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_snprintf(name, sizeof(name), "JS Object (%s - %s)",
|
||||||
|
clasp->name, si->GetJSClass()->name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
XPCJSRuntime::NoteCustomGCThingXPCOMChildren(js::Class* clasp, JSObject* obj,
|
||||||
|
nsCycleCollectionTraversalCallback& cb) const
|
||||||
|
{
|
||||||
|
if (clasp != &XPC_WN_Tearoff_JSClass) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A tearoff holds a strong reference to its native object
|
||||||
|
// (see XPCWrappedNative::FlatJSObjectFinalized). Its XPCWrappedNative
|
||||||
|
// will be held alive through the parent of the JSObject of the tearoff.
|
||||||
|
XPCWrappedNativeTearOff *to =
|
||||||
|
static_cast<XPCWrappedNativeTearOff*>(xpc_GetJSPrivate(obj));
|
||||||
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "xpc_GetJSPrivate(obj)->mNative");
|
||||||
|
cb.NoteXPCOMChild(to->GetNative());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
XPCJSRuntime::DeferredRelease(nsISupports *obj)
|
XPCJSRuntime::DeferredRelease(nsISupports *obj)
|
||||||
{
|
{
|
||||||
|
|
|
@ -372,38 +372,10 @@ nsXPConnect::UsefulToMergeZones()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
class nsXPConnectParticipant: public nsCycleCollectionParticipant
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static NS_METHOD RootImpl(void *n)
|
|
||||||
{
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
static NS_METHOD UnlinkImpl(void *n)
|
|
||||||
{
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
static NS_METHOD UnrootImpl(void *n)
|
|
||||||
{
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
static NS_METHOD_(void) UnmarkIfPurpleImpl(void *n)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
static NS_METHOD TraverseImpl(nsXPConnectParticipant *that, void *n,
|
|
||||||
nsCycleCollectionTraversalCallback &cb);
|
|
||||||
};
|
|
||||||
|
|
||||||
static const CCParticipantVTable<nsXPConnectParticipant>::Type
|
|
||||||
XPConnect_cycleCollectorGlobal =
|
|
||||||
{
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_NATIVE_VTABLE(nsXPConnectParticipant)
|
|
||||||
};
|
|
||||||
|
|
||||||
nsCycleCollectionParticipant *
|
nsCycleCollectionParticipant *
|
||||||
nsXPConnect::GetParticipant()
|
nsXPConnect::GetParticipant()
|
||||||
{
|
{
|
||||||
return XPConnect_cycleCollectorGlobal.GetParticipant();
|
return GetRuntime()->GCThingParticipant();
|
||||||
}
|
}
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
|
@ -413,56 +385,6 @@ xpc_GCThingIsGrayCCThing(void *thing)
|
||||||
xpc_IsGrayGCThing(thing);
|
xpc_IsGrayGCThing(thing);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TraversalTracer : public JSTracer
|
|
||||||
{
|
|
||||||
TraversalTracer(nsCycleCollectionTraversalCallback &aCb) : cb(aCb)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
nsCycleCollectionTraversalCallback &cb;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
NoteJSChild(JSTracer *trc, void *thing, JSGCTraceKind kind)
|
|
||||||
{
|
|
||||||
TraversalTracer *tracer = static_cast<TraversalTracer*>(trc);
|
|
||||||
|
|
||||||
// Don't traverse non-gray objects, unless we want all traces.
|
|
||||||
if (!xpc_IsGrayGCThing(thing) && !tracer->cb.WantAllTraces())
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This function needs to be careful to avoid stack overflow. Normally, when
|
|
||||||
* AddToCCKind is true, the recursion terminates immediately as we just add
|
|
||||||
* |thing| to the CC graph. So overflow is only possible when there are long
|
|
||||||
* chains of non-AddToCCKind GC things. Currently, this only can happen via
|
|
||||||
* shape parent pointers. The special JSTRACE_SHAPE case below handles
|
|
||||||
* parent pointers iteratively, rather than recursively, to avoid overflow.
|
|
||||||
*/
|
|
||||||
if (AddToCCKind(kind)) {
|
|
||||||
if (MOZ_UNLIKELY(tracer->cb.WantDebugInfo())) {
|
|
||||||
// based on DumpNotify in jsapi.c
|
|
||||||
if (tracer->debugPrinter) {
|
|
||||||
char buffer[200];
|
|
||||||
tracer->debugPrinter(trc, buffer, sizeof(buffer));
|
|
||||||
tracer->cb.NoteNextEdgeName(buffer);
|
|
||||||
} else if (tracer->debugPrintIndex != (size_t)-1) {
|
|
||||||
char buffer[200];
|
|
||||||
JS_snprintf(buffer, sizeof(buffer), "%s[%lu]",
|
|
||||||
static_cast<const char *>(tracer->debugPrintArg),
|
|
||||||
tracer->debugPrintIndex);
|
|
||||||
tracer->cb.NoteNextEdgeName(buffer);
|
|
||||||
} else {
|
|
||||||
tracer->cb.NoteNextEdgeName(static_cast<const char*>(tracer->debugPrintArg));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tracer->cb.NoteJSChild(thing);
|
|
||||||
} else if (kind == JSTRACE_SHAPE) {
|
|
||||||
JS_TraceShapeCycleCollectorChildren(trc, thing);
|
|
||||||
} else if (kind != JSTRACE_STRING) {
|
|
||||||
JS_TraceChildren(trc, thing, kind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
xpc_MarkInCCGeneration(nsISupports* aVariant, uint32_t aGeneration)
|
xpc_MarkInCCGeneration(nsISupports* aVariant, uint32_t aGeneration)
|
||||||
{
|
{
|
||||||
|
@ -488,154 +410,6 @@ xpc_TryUnmarkWrappedGrayObject(nsISupports* aWrappedJS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
|
||||||
DescribeGCThing(bool isMarked, void *p, JSGCTraceKind traceKind,
|
|
||||||
nsCycleCollectionTraversalCallback &cb)
|
|
||||||
{
|
|
||||||
if (cb.WantDebugInfo()) {
|
|
||||||
char name[72];
|
|
||||||
if (traceKind == JSTRACE_OBJECT) {
|
|
||||||
JSObject *obj = static_cast<JSObject*>(p);
|
|
||||||
js::Class *clasp = js::GetObjectClass(obj);
|
|
||||||
XPCNativeScriptableInfo *si = nullptr;
|
|
||||||
|
|
||||||
if (IS_PROTO_CLASS(clasp)) {
|
|
||||||
XPCWrappedNativeProto *p =
|
|
||||||
static_cast<XPCWrappedNativeProto*>(xpc_GetJSPrivate(obj));
|
|
||||||
si = p->GetScriptableInfo();
|
|
||||||
}
|
|
||||||
if (si) {
|
|
||||||
JS_snprintf(name, sizeof(name), "JS Object (%s - %s)",
|
|
||||||
clasp->name, si->GetJSClass()->name);
|
|
||||||
} else if (clasp == &js::FunctionClass) {
|
|
||||||
JSFunction *fun = JS_GetObjectFunction(obj);
|
|
||||||
JSString *str = JS_GetFunctionDisplayId(fun);
|
|
||||||
if (str) {
|
|
||||||
NS_ConvertUTF16toUTF8 fname(JS_GetInternedStringChars(str));
|
|
||||||
JS_snprintf(name, sizeof(name),
|
|
||||||
"JS Object (Function - %s)", fname.get());
|
|
||||||
} else {
|
|
||||||
JS_snprintf(name, sizeof(name), "JS Object (Function)");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
JS_snprintf(name, sizeof(name), "JS Object (%s)",
|
|
||||||
clasp->name);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
static const char trace_types[][11] = {
|
|
||||||
"Object",
|
|
||||||
"String",
|
|
||||||
"Script",
|
|
||||||
"LazyScript",
|
|
||||||
"IonCode",
|
|
||||||
"Shape",
|
|
||||||
"BaseShape",
|
|
||||||
"TypeObject",
|
|
||||||
};
|
|
||||||
JS_STATIC_ASSERT(NS_ARRAY_LENGTH(trace_types) == JSTRACE_LAST + 1);
|
|
||||||
JS_snprintf(name, sizeof(name), "JS %s", trace_types[traceKind]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable printing global for objects while we figure out ObjShrink fallout.
|
|
||||||
cb.DescribeGCedNode(isMarked, name);
|
|
||||||
} else {
|
|
||||||
cb.DescribeGCedNode(isMarked, "JS Object");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
NoteJSChildTracerShim(JSTracer *trc, void **thingp, JSGCTraceKind kind)
|
|
||||||
{
|
|
||||||
NoteJSChild(trc, *thingp, kind);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
NoteGCThingJSChildren(JSRuntime *rt, void *p, JSGCTraceKind traceKind,
|
|
||||||
nsCycleCollectionTraversalCallback &cb)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(rt);
|
|
||||||
TraversalTracer trc(cb);
|
|
||||||
JS_TracerInit(&trc, rt, NoteJSChildTracerShim);
|
|
||||||
trc.eagerlyTraceWeakMaps = DoNotTraceWeakMaps;
|
|
||||||
JS_TraceChildren(&trc, p, traceKind);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
NoteGCThingXPCOMChildren(js::Class *clasp, JSObject *obj,
|
|
||||||
nsCycleCollectionTraversalCallback &cb)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(clasp);
|
|
||||||
MOZ_ASSERT(clasp == js::GetObjectClass(obj));
|
|
||||||
|
|
||||||
if (clasp == &XPC_WN_Tearoff_JSClass) {
|
|
||||||
// A tearoff holds a strong reference to its native object
|
|
||||||
// (see XPCWrappedNative::FlatJSObjectFinalized). Its XPCWrappedNative
|
|
||||||
// will be held alive through the parent of the JSObject of the tearoff.
|
|
||||||
XPCWrappedNativeTearOff *to =
|
|
||||||
static_cast<XPCWrappedNativeTearOff*>(xpc_GetJSPrivate(obj));
|
|
||||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "xpc_GetJSPrivate(obj)->mNative");
|
|
||||||
cb.NoteXPCOMChild(to->GetNative());
|
|
||||||
}
|
|
||||||
// XXX This test does seem fragile, we should probably whitelist classes
|
|
||||||
// that do hold a strong reference, but that might not be possible.
|
|
||||||
else if (clasp->flags & JSCLASS_HAS_PRIVATE &&
|
|
||||||
clasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) {
|
|
||||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "xpc_GetJSPrivate(obj)");
|
|
||||||
cb.NoteXPCOMChild(static_cast<nsISupports*>(xpc_GetJSPrivate(obj)));
|
|
||||||
} else {
|
|
||||||
const DOMClass* domClass = GetDOMClass(obj);
|
|
||||||
if (domClass) {
|
|
||||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "UnwrapDOMObject(obj)");
|
|
||||||
if (domClass->mDOMObjectIsISupports) {
|
|
||||||
cb.NoteXPCOMChild(UnwrapDOMObject<nsISupports>(obj));
|
|
||||||
} else if (domClass->mParticipant) {
|
|
||||||
cb.NoteNativeChild(UnwrapDOMObject<void>(obj),
|
|
||||||
domClass->mParticipant);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum TraverseSelect {
|
|
||||||
TRAVERSE_CPP,
|
|
||||||
TRAVERSE_FULL
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
TraverseGCThing(TraverseSelect ts, void *p, JSGCTraceKind traceKind,
|
|
||||||
nsCycleCollectionTraversalCallback &cb)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(traceKind == js::GCThingTraceKind(p));
|
|
||||||
bool isMarkedGray = xpc_IsGrayGCThing(p);
|
|
||||||
|
|
||||||
if (ts == TRAVERSE_FULL)
|
|
||||||
DescribeGCThing(!isMarkedGray, p, traceKind, cb);
|
|
||||||
|
|
||||||
// If this object is alive, then all of its children are alive. For JS objects,
|
|
||||||
// the black-gray invariant ensures the children are also marked black. For C++
|
|
||||||
// objects, the ref count from this object will keep them alive. Thus we don't
|
|
||||||
// need to trace our children, unless we are debugging using WantAllTraces.
|
|
||||||
if (!isMarkedGray && !cb.WantAllTraces())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (ts == TRAVERSE_FULL)
|
|
||||||
NoteGCThingJSChildren(nsXPConnect::GetRuntimeInstance()->Runtime(),
|
|
||||||
p, traceKind, cb);
|
|
||||||
|
|
||||||
if (traceKind == JSTRACE_OBJECT) {
|
|
||||||
JSObject *obj = static_cast<JSObject*>(p);
|
|
||||||
NoteGCThingXPCOMChildren(js::GetObjectClass(obj), obj, cb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_METHOD
|
|
||||||
nsXPConnectParticipant::TraverseImpl(nsXPConnectParticipant *that, void *p,
|
|
||||||
nsCycleCollectionTraversalCallback &cb)
|
|
||||||
{
|
|
||||||
TraverseGCThing(TRAVERSE_FULL, p, js::GCThingTraceKind(p), cb);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
nsCycleCollectionParticipant*
|
nsCycleCollectionParticipant*
|
||||||
nsXPConnect::JSContextParticipant()
|
nsXPConnect::JSContextParticipant()
|
||||||
|
@ -1828,118 +1602,6 @@ SetLocationForGlobal(JSObject *global, nsIURI *locationURI)
|
||||||
|
|
||||||
} // namespace xpc
|
} // namespace xpc
|
||||||
|
|
||||||
static void
|
|
||||||
NoteJSChildGrayWrapperShim(void *data, void *thing)
|
|
||||||
{
|
|
||||||
TraversalTracer *trc = static_cast<TraversalTracer*>(data);
|
|
||||||
NoteJSChild(trc, thing, js::GCThingTraceKind(thing));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
TraverseObjectShim(void *data, void *thing)
|
|
||||||
{
|
|
||||||
nsCycleCollectionTraversalCallback *cb =
|
|
||||||
static_cast<nsCycleCollectionTraversalCallback*>(data);
|
|
||||||
|
|
||||||
MOZ_ASSERT(js::GCThingTraceKind(thing) == JSTRACE_OBJECT);
|
|
||||||
TraverseGCThing(TRAVERSE_CPP, thing, JSTRACE_OBJECT, *cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The cycle collection participant for a Zone is intended to produce the same
|
|
||||||
* results as if all of the gray GCthings in a zone were merged into a single node,
|
|
||||||
* except for self-edges. This avoids the overhead of representing all of the GCthings in
|
|
||||||
* the zone in the cycle collector graph, which should be much faster if many of
|
|
||||||
* the GCthings in the zone are gray.
|
|
||||||
*
|
|
||||||
* Zone merging should not always be used, because it is a conservative
|
|
||||||
* approximation of the true cycle collector graph that can incorrectly identify some
|
|
||||||
* garbage objects as being live. For instance, consider two cycles that pass through a
|
|
||||||
* zone, where one is garbage and the other is live. If we merge the entire
|
|
||||||
* zone, the cycle collector will think that both are alive.
|
|
||||||
*
|
|
||||||
* We don't have to worry about losing track of a garbage cycle, because any such garbage
|
|
||||||
* cycle incorrectly identified as live must contain at least one C++ to JS edge, and
|
|
||||||
* XPConnect will always add the C++ object to the CC graph. (This is in contrast to pure
|
|
||||||
* C++ garbage cycles, which must always be properly identified, because we clear the
|
|
||||||
* purple buffer during every CC, which may contain the last reference to a garbage
|
|
||||||
* cycle.)
|
|
||||||
*/
|
|
||||||
class JSZoneParticipant : public nsCycleCollectionParticipant
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static NS_METHOD TraverseImpl(JSZoneParticipant *that, void *p,
|
|
||||||
nsCycleCollectionTraversalCallback &cb)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(!cb.WantAllTraces());
|
|
||||||
JS::Zone *zone = static_cast<JS::Zone *>(p);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We treat the zone as being gray. We handle non-gray GCthings in the
|
|
||||||
* zone by not reporting their children to the CC. The black-gray invariant
|
|
||||||
* ensures that any JS children will also be non-gray, and thus don't need to be
|
|
||||||
* added to the graph. For C++ children, not representing the edge from the
|
|
||||||
* non-gray JS GCthings to the C++ object will keep the child alive.
|
|
||||||
*
|
|
||||||
* We don't allow zone merging in a WantAllTraces CC, because then these
|
|
||||||
* assumptions don't hold.
|
|
||||||
*/
|
|
||||||
cb.DescribeGCedNode(false, "JS Zone");
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Every JS child of everything in the zone is either in the zone
|
|
||||||
* or is a cross-compartment wrapper. In the former case, we don't need to
|
|
||||||
* represent these edges in the CC graph because JS objects are not ref counted.
|
|
||||||
* In the latter case, the JS engine keeps a map of these wrappers, which we
|
|
||||||
* iterate over. Edges between compartments in the same zone will add
|
|
||||||
* unnecessary loop edges to the graph (bug 842137).
|
|
||||||
*/
|
|
||||||
TraversalTracer trc(cb);
|
|
||||||
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
|
|
||||||
JS_TracerInit(&trc, rt, NoteJSChildTracerShim);
|
|
||||||
trc.eagerlyTraceWeakMaps = DoNotTraceWeakMaps;
|
|
||||||
js::VisitGrayWrapperTargets(zone, NoteJSChildGrayWrapperShim, &trc);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* To find C++ children of things in the zone, we scan every JS Object in
|
|
||||||
* the zone. Only JS Objects can have C++ children.
|
|
||||||
*/
|
|
||||||
js::IterateGrayObjects(zone, TraverseObjectShim, &cb);
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static NS_METHOD RootImpl(void *p)
|
|
||||||
{
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static NS_METHOD UnlinkImpl(void *p)
|
|
||||||
{
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static NS_METHOD UnrootImpl(void *p)
|
|
||||||
{
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static NS_METHOD_(void) UnmarkIfPurpleImpl(void *n)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const CCParticipantVTable<JSZoneParticipant>::Type
|
|
||||||
JSZone_cycleCollectorGlobal = {
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_NATIVE_VTABLE(JSZoneParticipant)
|
|
||||||
};
|
|
||||||
|
|
||||||
nsCycleCollectionParticipant *
|
|
||||||
xpc_JSZoneParticipant()
|
|
||||||
{
|
|
||||||
return JSZone_cycleCollectorGlobal.GetParticipant();
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsXPConnect::SetDebugModeWhenPossible(bool mode, bool allowSyncDisable)
|
nsXPConnect::SetDebugModeWhenPossible(bool mode, bool allowSyncDisable)
|
||||||
{
|
{
|
||||||
|
|
|
@ -506,7 +506,7 @@ public:
|
||||||
virtual void NotifyLeaveCycleCollectionThread(); // DONE
|
virtual void NotifyLeaveCycleCollectionThread(); // DONE
|
||||||
virtual void NotifyEnterMainThread(); // DONE
|
virtual void NotifyEnterMainThread(); // DONE
|
||||||
virtual nsresult BeginCycleCollection(nsCycleCollectionNoteRootCallback &cb); // DONE
|
virtual nsresult BeginCycleCollection(nsCycleCollectionNoteRootCallback &cb); // DONE
|
||||||
virtual nsCycleCollectionParticipant *GetParticipant();
|
virtual nsCycleCollectionParticipant *GetParticipant(); // DONE
|
||||||
virtual bool UsefulToMergeZones();
|
virtual bool UsefulToMergeZones();
|
||||||
virtual void FixWeakMappingGrayBits(); // DONE
|
virtual void FixWeakMappingGrayBits(); // DONE
|
||||||
virtual bool NeedCollect(); // DONE
|
virtual bool NeedCollect(); // DONE
|
||||||
|
@ -619,7 +619,6 @@ public:
|
||||||
// In the current xpconnect system there can only be one XPCJSRuntime.
|
// In the current xpconnect system there can only be one XPCJSRuntime.
|
||||||
// So, xpconnect can only be used on one JSRuntime within the process.
|
// So, xpconnect can only be used on one JSRuntime within the process.
|
||||||
|
|
||||||
// no virtuals. no refcounting.
|
|
||||||
class XPCJSContextStack;
|
class XPCJSContextStack;
|
||||||
class XPCIncrementalReleaseRunnable;
|
class XPCIncrementalReleaseRunnable;
|
||||||
class XPCJSRuntime : public mozilla::CycleCollectedJSRuntime
|
class XPCJSRuntime : public mozilla::CycleCollectedJSRuntime
|
||||||
|
@ -681,6 +680,13 @@ public:
|
||||||
|
|
||||||
JSBool OnJSContextNew(JSContext* cx);
|
JSBool OnJSContextNew(JSContext* cx);
|
||||||
|
|
||||||
|
virtual bool
|
||||||
|
DescribeCustomObjects(JSObject* aObject, js::Class* aClasp,
|
||||||
|
char (&aName)[72]) const;
|
||||||
|
virtual bool
|
||||||
|
NoteCustomGCThingXPCOMChildren(js::Class* aClasp, JSObject* aObj,
|
||||||
|
nsCycleCollectionTraversalCallback& aCb) const;
|
||||||
|
|
||||||
bool DeferredRelease(nsISupports* obj);
|
bool DeferredRelease(nsISupports* obj);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,17 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||||
|
#include "mozilla/dom/BindingUtils.h"
|
||||||
|
#include "mozilla/dom/DOMJSClass.h"
|
||||||
#include "jsfriendapi.h"
|
#include "jsfriendapi.h"
|
||||||
|
#include "jsprf.h"
|
||||||
#include "nsCycleCollectionNoteRootCallback.h"
|
#include "nsCycleCollectionNoteRootCallback.h"
|
||||||
#include "nsCycleCollectionParticipant.h"
|
#include "nsCycleCollectionParticipant.h"
|
||||||
#include "nsLayoutStatics.h"
|
#include "nsLayoutStatics.h"
|
||||||
#include "xpcpublic.h"
|
#include "xpcpublic.h"
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
|
using namespace mozilla::dom;
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
AddToCCKind(JSGCTraceKind kind)
|
AddToCCKind(JSGCTraceKind kind)
|
||||||
|
@ -263,10 +267,147 @@ NoteJSHolder(void *holder, nsScriptObjectTracer *&tracer, void *arg)
|
||||||
return PL_DHASH_NEXT;
|
return PL_DHASH_NEXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_METHOD
|
||||||
|
JSGCThingParticipant::TraverseImpl(JSGCThingParticipant* that, void* p,
|
||||||
|
nsCycleCollectionTraversalCallback& cb)
|
||||||
|
{
|
||||||
|
CycleCollectedJSRuntime* runtime = reinterpret_cast<CycleCollectedJSRuntime*>
|
||||||
|
(reinterpret_cast<char*>(that) -
|
||||||
|
offsetof(CycleCollectedJSRuntime, mGCThingCycleCollectorGlobal));
|
||||||
|
|
||||||
|
runtime->TraverseGCThing(CycleCollectedJSRuntime::TRAVERSE_FULL,
|
||||||
|
p, js::GCThingTraceKind(p), cb);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NB: This is only used to initialize the participant in
|
||||||
|
// CycleCollectedJSRuntime. It should never be used directly.
|
||||||
|
static const CCParticipantVTable<JSGCThingParticipant>::Type
|
||||||
|
sGCThingCycleCollectorGlobal =
|
||||||
|
{
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_NATIVE_VTABLE(JSGCThingParticipant)
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_METHOD
|
||||||
|
JSZoneParticipant::TraverseImpl(JSZoneParticipant* that, void* p,
|
||||||
|
nsCycleCollectionTraversalCallback& cb)
|
||||||
|
{
|
||||||
|
CycleCollectedJSRuntime* runtime = reinterpret_cast<CycleCollectedJSRuntime*>
|
||||||
|
(reinterpret_cast<char*>(that) -
|
||||||
|
offsetof(CycleCollectedJSRuntime, mJSZoneCycleCollectorGlobal));
|
||||||
|
|
||||||
|
MOZ_ASSERT(!cb.WantAllTraces());
|
||||||
|
JS::Zone* zone = static_cast<JS::Zone*>(p);
|
||||||
|
|
||||||
|
runtime->TraverseZone(zone, cb);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TraversalTracer : public JSTracer
|
||||||
|
{
|
||||||
|
TraversalTracer(nsCycleCollectionTraversalCallback& aCb) : mCb(aCb)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
nsCycleCollectionTraversalCallback& mCb;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
NoteJSChild(JSTracer* aTrc, void* aThing, JSGCTraceKind aTraceKind)
|
||||||
|
{
|
||||||
|
TraversalTracer* tracer = static_cast<TraversalTracer*>(aTrc);
|
||||||
|
|
||||||
|
// Don't traverse non-gray objects, unless we want all traces.
|
||||||
|
if (!xpc_IsGrayGCThing(aThing) && !tracer->mCb.WantAllTraces()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function needs to be careful to avoid stack overflow. Normally, when
|
||||||
|
* AddToCCKind is true, the recursion terminates immediately as we just add
|
||||||
|
* |thing| to the CC graph. So overflow is only possible when there are long
|
||||||
|
* chains of non-AddToCCKind GC things. Currently, this only can happen via
|
||||||
|
* shape parent pointers. The special JSTRACE_SHAPE case below handles
|
||||||
|
* parent pointers iteratively, rather than recursively, to avoid overflow.
|
||||||
|
*/
|
||||||
|
if (AddToCCKind(aTraceKind)) {
|
||||||
|
if (MOZ_UNLIKELY(tracer->mCb.WantDebugInfo())) {
|
||||||
|
// based on DumpNotify in jsapi.c
|
||||||
|
if (tracer->debugPrinter) {
|
||||||
|
char buffer[200];
|
||||||
|
tracer->debugPrinter(aTrc, buffer, sizeof(buffer));
|
||||||
|
tracer->mCb.NoteNextEdgeName(buffer);
|
||||||
|
} else if (tracer->debugPrintIndex != (size_t)-1) {
|
||||||
|
char buffer[200];
|
||||||
|
JS_snprintf(buffer, sizeof(buffer), "%s[%lu]",
|
||||||
|
static_cast<const char *>(tracer->debugPrintArg),
|
||||||
|
tracer->debugPrintIndex);
|
||||||
|
tracer->mCb.NoteNextEdgeName(buffer);
|
||||||
|
} else {
|
||||||
|
tracer->mCb.NoteNextEdgeName(static_cast<const char*>(tracer->debugPrintArg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tracer->mCb.NoteJSChild(aThing);
|
||||||
|
} else if (aTraceKind == JSTRACE_SHAPE) {
|
||||||
|
JS_TraceShapeCycleCollectorChildren(aTrc, aThing);
|
||||||
|
} else if (aTraceKind != JSTRACE_STRING) {
|
||||||
|
JS_TraceChildren(aTrc, aThing, aTraceKind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
NoteJSChildTracerShim(JSTracer* aTrc, void** aThingp, JSGCTraceKind aTraceKind)
|
||||||
|
{
|
||||||
|
NoteJSChild(aTrc, *aThingp, aTraceKind);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
NoteJSChildGrayWrapperShim(void* aData, void* aThing)
|
||||||
|
{
|
||||||
|
TraversalTracer* trc = static_cast<TraversalTracer*>(aData);
|
||||||
|
NoteJSChild(trc, aThing, js::GCThingTraceKind(aThing));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The cycle collection participant for a Zone is intended to produce the same
|
||||||
|
* results as if all of the gray GCthings in a zone were merged into a single node,
|
||||||
|
* except for self-edges. This avoids the overhead of representing all of the GCthings in
|
||||||
|
* the zone in the cycle collector graph, which should be much faster if many of
|
||||||
|
* the GCthings in the zone are gray.
|
||||||
|
*
|
||||||
|
* Zone merging should not always be used, because it is a conservative
|
||||||
|
* approximation of the true cycle collector graph that can incorrectly identify some
|
||||||
|
* garbage objects as being live. For instance, consider two cycles that pass through a
|
||||||
|
* zone, where one is garbage and the other is live. If we merge the entire
|
||||||
|
* zone, the cycle collector will think that both are alive.
|
||||||
|
*
|
||||||
|
* We don't have to worry about losing track of a garbage cycle, because any such garbage
|
||||||
|
* cycle incorrectly identified as live must contain at least one C++ to JS edge, and
|
||||||
|
* XPConnect will always add the C++ object to the CC graph. (This is in contrast to pure
|
||||||
|
* C++ garbage cycles, which must always be properly identified, because we clear the
|
||||||
|
* purple buffer during every CC, which may contain the last reference to a garbage
|
||||||
|
* cycle.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
// NB: This is only used to initialize the participant in
|
||||||
|
// CycleCollectedJSRuntime. It should never be used directly.
|
||||||
|
static const CCParticipantVTable<JSZoneParticipant>::Type
|
||||||
|
sJSZoneCycleCollectorGlobal = {
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_NATIVE_VTABLE(JSZoneParticipant)
|
||||||
|
};
|
||||||
|
|
||||||
|
// XXXkhuey this is totally wrong ...
|
||||||
|
nsCycleCollectionParticipant*
|
||||||
|
xpc_JSZoneParticipant()
|
||||||
|
{
|
||||||
|
return sJSZoneCycleCollectorGlobal.GetParticipant();
|
||||||
|
}
|
||||||
|
|
||||||
CycleCollectedJSRuntime::CycleCollectedJSRuntime(uint32_t aMaxbytes,
|
CycleCollectedJSRuntime::CycleCollectedJSRuntime(uint32_t aMaxbytes,
|
||||||
JSUseHelperThreads aUseHelperThreads,
|
JSUseHelperThreads aUseHelperThreads,
|
||||||
bool aExpectUnrootedGlobals)
|
bool aExpectUnrootedGlobals)
|
||||||
: mJSRuntime(nullptr)
|
: mGCThingCycleCollectorGlobal(sGCThingCycleCollectorGlobal),
|
||||||
|
mJSZoneCycleCollectorGlobal(sJSZoneCycleCollectorGlobal),
|
||||||
|
mJSRuntime(nullptr)
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
, mObjectToUnlink(nullptr)
|
, mObjectToUnlink(nullptr)
|
||||||
, mExpectUnrootedGlobals(aExpectUnrootedGlobals)
|
, mExpectUnrootedGlobals(aExpectUnrootedGlobals)
|
||||||
|
@ -302,6 +443,183 @@ CycleCollectedJSRuntime::MaybeTraceGlobals(JSTracer* aTracer) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CycleCollectedJSRuntime::DescribeGCThing(bool aIsMarked, void* aThing,
|
||||||
|
JSGCTraceKind aTraceKind,
|
||||||
|
nsCycleCollectionTraversalCallback& aCb) const
|
||||||
|
{
|
||||||
|
if (!aCb.WantDebugInfo()) {
|
||||||
|
aCb.DescribeGCedNode(aIsMarked, "JS Object");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char name[72];
|
||||||
|
if (aTraceKind == JSTRACE_OBJECT) {
|
||||||
|
JSObject* obj = static_cast<JSObject*>(aThing);
|
||||||
|
js::Class* clasp = js::GetObjectClass(obj);
|
||||||
|
|
||||||
|
// Give the subclass a chance to do something
|
||||||
|
if (DescribeCustomObjects(obj, clasp, name)) {
|
||||||
|
// Nothing else to do!
|
||||||
|
} else if (clasp == &js::FunctionClass) {
|
||||||
|
JSFunction* fun = JS_GetObjectFunction(obj);
|
||||||
|
JSString* str = JS_GetFunctionDisplayId(fun);
|
||||||
|
if (str) {
|
||||||
|
NS_ConvertUTF16toUTF8 fname(JS_GetInternedStringChars(str));
|
||||||
|
JS_snprintf(name, sizeof(name),
|
||||||
|
"JS Object (Function - %s)", fname.get());
|
||||||
|
} else {
|
||||||
|
JS_snprintf(name, sizeof(name), "JS Object (Function)");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
JS_snprintf(name, sizeof(name), "JS Object (%s)",
|
||||||
|
clasp->name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
static const char trace_types[][11] = {
|
||||||
|
"Object",
|
||||||
|
"String",
|
||||||
|
"Script",
|
||||||
|
"LazyScript",
|
||||||
|
"IonCode",
|
||||||
|
"Shape",
|
||||||
|
"BaseShape",
|
||||||
|
"TypeObject",
|
||||||
|
};
|
||||||
|
JS_STATIC_ASSERT(NS_ARRAY_LENGTH(trace_types) == JSTRACE_LAST + 1);
|
||||||
|
JS_snprintf(name, sizeof(name), "JS %s", trace_types[aTraceKind]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable printing global for objects while we figure out ObjShrink fallout.
|
||||||
|
aCb.DescribeGCedNode(aIsMarked, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CycleCollectedJSRuntime::NoteGCThingJSChildren(void* aThing,
|
||||||
|
JSGCTraceKind aTraceKind,
|
||||||
|
nsCycleCollectionTraversalCallback& aCb) const
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mJSRuntime);
|
||||||
|
TraversalTracer trc(aCb);
|
||||||
|
JS_TracerInit(&trc, mJSRuntime, NoteJSChildTracerShim);
|
||||||
|
trc.eagerlyTraceWeakMaps = DoNotTraceWeakMaps;
|
||||||
|
JS_TraceChildren(&trc, aThing, aTraceKind);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CycleCollectedJSRuntime::NoteGCThingXPCOMChildren(js::Class* aClasp, JSObject* aObj,
|
||||||
|
nsCycleCollectionTraversalCallback& aCb) const
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aClasp);
|
||||||
|
MOZ_ASSERT(aClasp == js::GetObjectClass(aObj));
|
||||||
|
|
||||||
|
if (NoteCustomGCThingXPCOMChildren(aClasp, aObj, aCb)) {
|
||||||
|
// Nothing else to do!
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// XXX This test does seem fragile, we should probably whitelist classes
|
||||||
|
// that do hold a strong reference, but that might not be possible.
|
||||||
|
else if (aClasp->flags & JSCLASS_HAS_PRIVATE &&
|
||||||
|
aClasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) {
|
||||||
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "js::GetObjectPrivate(obj)");
|
||||||
|
aCb.NoteXPCOMChild(static_cast<nsISupports*>(js::GetObjectPrivate(aObj)));
|
||||||
|
} else {
|
||||||
|
const DOMClass* domClass = GetDOMClass(aObj);
|
||||||
|
if (domClass) {
|
||||||
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "UnwrapDOMObject(obj)");
|
||||||
|
if (domClass->mDOMObjectIsISupports) {
|
||||||
|
aCb.NoteXPCOMChild(UnwrapDOMObject<nsISupports>(aObj));
|
||||||
|
} else if (domClass->mParticipant) {
|
||||||
|
aCb.NoteNativeChild(UnwrapDOMObject<void>(aObj),
|
||||||
|
domClass->mParticipant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CycleCollectedJSRuntime::TraverseGCThing(TraverseSelect aTs, void* aThing,
|
||||||
|
JSGCTraceKind aTraceKind,
|
||||||
|
nsCycleCollectionTraversalCallback& aCb)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aTraceKind == js::GCThingTraceKind(aThing));
|
||||||
|
bool isMarkedGray = xpc_IsGrayGCThing(aThing);
|
||||||
|
|
||||||
|
if (aTs == TRAVERSE_FULL) {
|
||||||
|
DescribeGCThing(!isMarkedGray, aThing, aTraceKind, aCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this object is alive, then all of its children are alive. For JS objects,
|
||||||
|
// the black-gray invariant ensures the children are also marked black. For C++
|
||||||
|
// objects, the ref count from this object will keep them alive. Thus we don't
|
||||||
|
// need to trace our children, unless we are debugging using WantAllTraces.
|
||||||
|
if (!isMarkedGray && !aCb.WantAllTraces()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aTs == TRAVERSE_FULL) {
|
||||||
|
NoteGCThingJSChildren(aThing, aTraceKind, aCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aTraceKind == JSTRACE_OBJECT) {
|
||||||
|
JSObject* obj = static_cast<JSObject*>(aThing);
|
||||||
|
NoteGCThingXPCOMChildren(js::GetObjectClass(obj), obj, aCb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TraverseObjectShimClosure {
|
||||||
|
nsCycleCollectionTraversalCallback& cb;
|
||||||
|
CycleCollectedJSRuntime* self;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
CycleCollectedJSRuntime::TraverseZone(JS::Zone* aZone,
|
||||||
|
nsCycleCollectionTraversalCallback& aCb)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We treat the zone as being gray. We handle non-gray GCthings in the
|
||||||
|
* zone by not reporting their children to the CC. The black-gray invariant
|
||||||
|
* ensures that any JS children will also be non-gray, and thus don't need to be
|
||||||
|
* added to the graph. For C++ children, not representing the edge from the
|
||||||
|
* non-gray JS GCthings to the C++ object will keep the child alive.
|
||||||
|
*
|
||||||
|
* We don't allow zone merging in a WantAllTraces CC, because then these
|
||||||
|
* assumptions don't hold.
|
||||||
|
*/
|
||||||
|
aCb.DescribeGCedNode(false, "JS Zone");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Every JS child of everything in the zone is either in the zone
|
||||||
|
* or is a cross-compartment wrapper. In the former case, we don't need to
|
||||||
|
* represent these edges in the CC graph because JS objects are not ref counted.
|
||||||
|
* In the latter case, the JS engine keeps a map of these wrappers, which we
|
||||||
|
* iterate over. Edges between compartments in the same zone will add
|
||||||
|
* unnecessary loop edges to the graph (bug 842137).
|
||||||
|
*/
|
||||||
|
TraversalTracer trc(aCb);
|
||||||
|
JS_TracerInit(&trc, mJSRuntime, NoteJSChildTracerShim);
|
||||||
|
trc.eagerlyTraceWeakMaps = DoNotTraceWeakMaps;
|
||||||
|
js::VisitGrayWrapperTargets(aZone, NoteJSChildGrayWrapperShim, &trc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To find C++ children of things in the zone, we scan every JS Object in
|
||||||
|
* the zone. Only JS Objects can have C++ children.
|
||||||
|
*/
|
||||||
|
TraverseObjectShimClosure closure = { aCb, this };
|
||||||
|
js::IterateGrayObjects(aZone, TraverseObjectShim, &closure);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ void
|
||||||
|
CycleCollectedJSRuntime::TraverseObjectShim(void* aData, void* aThing)
|
||||||
|
{
|
||||||
|
TraverseObjectShimClosure* closure =
|
||||||
|
static_cast<TraverseObjectShimClosure*>(aData);
|
||||||
|
|
||||||
|
MOZ_ASSERT(js::GCThingTraceKind(aThing) == JSTRACE_OBJECT);
|
||||||
|
closure->self->TraverseGCThing(CycleCollectedJSRuntime::TRAVERSE_CPP, aThing,
|
||||||
|
JSTRACE_OBJECT, closure->cb);
|
||||||
|
}
|
||||||
|
|
||||||
// For all JS objects that are held by native objects but aren't held
|
// For all JS objects that are held by native objects but aren't held
|
||||||
// through rooting or locking, we need to add all the native objects that
|
// through rooting or locking, we need to add all the native objects that
|
||||||
// hold them so that the JS objects are colored correctly in the cycle
|
// hold them so that the JS objects are colored correctly in the cycle
|
||||||
|
@ -396,6 +714,18 @@ CycleCollectedJSRuntime::JSContextParticipant()
|
||||||
return JSContext_cycleCollectorGlobal.GetParticipant();
|
return JSContext_cycleCollectorGlobal.GetParticipant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsCycleCollectionParticipant*
|
||||||
|
CycleCollectedJSRuntime::GCThingParticipant() const
|
||||||
|
{
|
||||||
|
return mGCThingCycleCollectorGlobal.GetParticipant();
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCycleCollectionParticipant*
|
||||||
|
CycleCollectedJSRuntime::ZoneParticipant() const
|
||||||
|
{
|
||||||
|
return mJSZoneCycleCollectorGlobal.GetParticipant();
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CycleCollectedJSRuntime::NotifyLeaveMainThread() const
|
CycleCollectedJSRuntime::NotifyLeaveMainThread() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,8 +7,10 @@
|
||||||
#ifndef mozilla_CycleCollectedJSRuntime_h__
|
#ifndef mozilla_CycleCollectedJSRuntime_h__
|
||||||
#define mozilla_CycleCollectedJSRuntime_h__
|
#define mozilla_CycleCollectedJSRuntime_h__
|
||||||
|
|
||||||
|
#include "jsprvtd.h"
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
|
|
||||||
|
#include "nsCycleCollectionParticipant.h"
|
||||||
#include "nsDataHashtable.h"
|
#include "nsDataHashtable.h"
|
||||||
#include "nsHashKeys.h"
|
#include "nsHashKeys.h"
|
||||||
|
|
||||||
|
@ -17,8 +19,63 @@ class nsScriptObjectTracer;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
|
class JSGCThingParticipant: public nsCycleCollectionParticipant
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static NS_METHOD RootImpl(void *n)
|
||||||
|
{
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NS_METHOD UnlinkImpl(void *n)
|
||||||
|
{
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NS_METHOD UnrootImpl(void *n)
|
||||||
|
{
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NS_METHOD_(void) UnmarkIfPurpleImpl(void *n)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static NS_METHOD TraverseImpl(JSGCThingParticipant *that, void *n,
|
||||||
|
nsCycleCollectionTraversalCallback &cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
class JSZoneParticipant : public nsCycleCollectionParticipant
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static NS_METHOD RootImpl(void *p)
|
||||||
|
{
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NS_METHOD UnlinkImpl(void *p)
|
||||||
|
{
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NS_METHOD UnrootImpl(void *p)
|
||||||
|
{
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NS_METHOD_(void) UnmarkIfPurpleImpl(void *n)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static NS_METHOD TraverseImpl(JSZoneParticipant *that, void *p,
|
||||||
|
nsCycleCollectionTraversalCallback &cb);
|
||||||
|
};
|
||||||
|
|
||||||
class CycleCollectedJSRuntime
|
class CycleCollectedJSRuntime
|
||||||
{
|
{
|
||||||
|
friend class JSGCThingParticipant;
|
||||||
|
friend class JSZoneParticipant;
|
||||||
protected:
|
protected:
|
||||||
CycleCollectedJSRuntime(uint32_t aMaxbytes,
|
CycleCollectedJSRuntime(uint32_t aMaxbytes,
|
||||||
JSUseHelperThreads aUseHelperThreads,
|
JSUseHelperThreads aUseHelperThreads,
|
||||||
|
@ -34,6 +91,44 @@ protected:
|
||||||
void MaybeTraceGlobals(JSTracer* aTracer) const;
|
void MaybeTraceGlobals(JSTracer* aTracer) const;
|
||||||
virtual void TraverseAdditionalNativeRoots(nsCycleCollectionNoteRootCallback& aCb) = 0;
|
virtual void TraverseAdditionalNativeRoots(nsCycleCollectionNoteRootCallback& aCb) = 0;
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
void
|
||||||
|
DescribeGCThing(bool aIsMarked, void* aThing, JSGCTraceKind aTraceKind,
|
||||||
|
nsCycleCollectionTraversalCallback& aCb) const;
|
||||||
|
|
||||||
|
virtual bool
|
||||||
|
DescribeCustomObjects(JSObject* aObject, js::Class* aClasp,
|
||||||
|
char (&aName)[72]) const = 0;
|
||||||
|
|
||||||
|
void
|
||||||
|
NoteGCThingJSChildren(void* aThing, JSGCTraceKind aTraceKind,
|
||||||
|
nsCycleCollectionTraversalCallback& aCb) const;
|
||||||
|
|
||||||
|
void
|
||||||
|
NoteGCThingXPCOMChildren(js::Class* aClasp, JSObject* aObj,
|
||||||
|
nsCycleCollectionTraversalCallback& aCb) const;
|
||||||
|
|
||||||
|
virtual bool
|
||||||
|
NoteCustomGCThingXPCOMChildren(js::Class* aClasp, JSObject* aObj,
|
||||||
|
nsCycleCollectionTraversalCallback& aCb) const = 0;
|
||||||
|
|
||||||
|
|
||||||
|
enum TraverseSelect {
|
||||||
|
TRAVERSE_CPP,
|
||||||
|
TRAVERSE_FULL
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
TraverseGCThing(TraverseSelect aTs, void* aThing,
|
||||||
|
JSGCTraceKind aTraceKind,
|
||||||
|
nsCycleCollectionTraversalCallback& aCb);
|
||||||
|
|
||||||
|
void
|
||||||
|
TraverseZone(JS::Zone* aZone, nsCycleCollectionTraversalCallback& aCb);
|
||||||
|
|
||||||
|
static void
|
||||||
|
TraverseObjectShim(void* aData, void* aThing);
|
||||||
|
|
||||||
void MaybeTraverseGlobals(nsCycleCollectionNoteRootCallback& aCb) const;
|
void MaybeTraverseGlobals(nsCycleCollectionNoteRootCallback& aCb) const;
|
||||||
|
|
||||||
void TraverseNativeRoots(nsCycleCollectionNoteRootCallback& aCb);
|
void TraverseNativeRoots(nsCycleCollectionNoteRootCallback& aCb);
|
||||||
|
@ -48,7 +143,10 @@ public:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// This returns the singleton nsCycleCollectionParticipant for JSContexts.
|
// This returns the singleton nsCycleCollectionParticipant for JSContexts.
|
||||||
static nsCycleCollectionParticipant *JSContextParticipant();
|
static nsCycleCollectionParticipant* JSContextParticipant();
|
||||||
|
|
||||||
|
nsCycleCollectionParticipant* GCThingParticipant() const;
|
||||||
|
nsCycleCollectionParticipant* ZoneParticipant() const;
|
||||||
|
|
||||||
bool NotifyLeaveMainThread() const;
|
bool NotifyLeaveMainThread() const;
|
||||||
void NotifyEnterCycleCollectionThread() const;
|
void NotifyEnterCycleCollectionThread() const;
|
||||||
|
@ -63,6 +161,12 @@ protected:
|
||||||
nsDataHashtable<nsPtrHashKey<void>, nsScriptObjectTracer*> mJSHolders;
|
nsDataHashtable<nsPtrHashKey<void>, nsScriptObjectTracer*> mJSHolders;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
typedef const CCParticipantVTable<JSGCThingParticipant>::Type GCThingParticipantVTable;
|
||||||
|
const GCThingParticipantVTable mGCThingCycleCollectorGlobal;
|
||||||
|
|
||||||
|
typedef const CCParticipantVTable<JSZoneParticipant>::Type JSZoneParticipantVTable;
|
||||||
|
const JSZoneParticipantVTable mJSZoneCycleCollectorGlobal;
|
||||||
|
|
||||||
JSRuntime* mJSRuntime;
|
JSRuntime* mJSRuntime;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
Загрузка…
Ссылка в новой задаче