зеркало из https://github.com/mozilla/gecko-dev.git
Bug 650161 - Fix up XPCJSRuntime object pointers on moving GC r=bholley
This commit is contained in:
Родитель
3bbcf48581
Коммит
9cf17436a8
|
@ -491,6 +491,14 @@ void XPCWrappedNativeTearOff::SetJSObject(JSObject* JSObj)
|
|||
mJSObject = JSObj;
|
||||
}
|
||||
|
||||
inline
|
||||
void XPCWrappedNativeTearOff::JSObjectMoved(JSObject *obj, const JSObject *old)
|
||||
{
|
||||
MOZ_ASSERT(!IsMarked());
|
||||
MOZ_ASSERT(mJSObject == old);
|
||||
mJSObject = obj;
|
||||
}
|
||||
|
||||
inline
|
||||
XPCWrappedNativeTearOff::~XPCWrappedNativeTearOff()
|
||||
{
|
||||
|
|
|
@ -789,19 +789,16 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp *fop,
|
|||
MOZ_ASSERT(!self->mGCIsRunning, "bad state");
|
||||
self->mGCIsRunning = true;
|
||||
|
||||
nsTArray<nsXPCWrappedJS*>* dyingWrappedJSArray =
|
||||
&self->mWrappedJSToReleaseArray;
|
||||
|
||||
// Add any wrappers whose JSObjects are to be finalized to
|
||||
// this array. Note that we do not want to be changing the
|
||||
// refcount of these wrappers.
|
||||
// We add them to the array now and Release the array members
|
||||
// later to avoid the posibility of doing any JS GCThing
|
||||
// allocations during the gc cycle.
|
||||
self->mWrappedJSMap->FindDyingJSObjects(dyingWrappedJSArray);
|
||||
self->mWrappedJSMap->UpdateWeakPointersAfterGC(self);
|
||||
|
||||
// Find dying scopes.
|
||||
XPCWrappedNativeScope::StartFinalizationPhaseOfGC(fop, self);
|
||||
XPCWrappedNativeScope::UpdateWeakPointersAfterGC(self);
|
||||
|
||||
self->mDoingFinalization = true;
|
||||
break;
|
||||
|
@ -816,7 +813,7 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp *fop,
|
|||
DoDeferredRelease(self->mWrappedJSToReleaseArray);
|
||||
|
||||
// Sweep scopes needing cleanup
|
||||
XPCWrappedNativeScope::FinishedFinalizationPhaseOfGC();
|
||||
XPCWrappedNativeScope::KillDyingScopes();
|
||||
|
||||
MOZ_ASSERT(self->mGCIsRunning, "bad state");
|
||||
self->mGCIsRunning = false;
|
||||
|
@ -971,6 +968,19 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp *fop,
|
|||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
XPCJSRuntime::MovingGCCallback(JSRuntime *rt, void *data)
|
||||
{
|
||||
// Called to fixup any weak GC thing pointers that may have been moved.
|
||||
|
||||
XPCJSRuntime *self = static_cast<XPCJSRuntime *>(data);
|
||||
|
||||
self->mWrappedJSMap->UpdateWeakPointersAfterGC(self);
|
||||
MOZ_ASSERT(self->WrappedJSToReleaseArray().IsEmpty());
|
||||
|
||||
XPCWrappedNativeScope::UpdateWeakPointersAfterGC(self);
|
||||
}
|
||||
|
||||
static void WatchdogMain(void *arg);
|
||||
class Watchdog;
|
||||
class WatchdogManager;
|
||||
|
@ -1537,6 +1547,7 @@ XPCJSRuntime::~XPCJSRuntime()
|
|||
// callback if we aren't careful. Null out the relevant callbacks.
|
||||
js::SetActivityCallback(Runtime(), nullptr, nullptr);
|
||||
JS_RemoveFinalizeCallback(Runtime(), FinalizeCallback);
|
||||
JS_RemoveMovingGCCallback(Runtime(), MovingGCCallback);
|
||||
|
||||
// Clear any pending exception. It might be an XPCWrappedJS, and if we try
|
||||
// to destroy it later we will crash.
|
||||
|
@ -3235,6 +3246,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
|
|||
JS_SetCompartmentNameCallback(runtime, CompartmentNameCallback);
|
||||
mPrevGCSliceCallback = JS::SetGCSliceCallback(runtime, GCSliceCallback);
|
||||
JS_AddFinalizeCallback(runtime, FinalizeCallback, nullptr);
|
||||
JS_AddMovingGCCallback(runtime, MovingGCCallback, this);
|
||||
JS_SetWrapObjectCallbacks(runtime, &WrapObjectCallbacks);
|
||||
js::SetPreserveWrapperCallback(runtime, PreserveWrapper);
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
|
|
|
@ -85,18 +85,44 @@ HashNativeKey(PLDHashTable *table, const void *key)
|
|||
// implement JSObject2WrappedJSMap...
|
||||
|
||||
void
|
||||
JSObject2WrappedJSMap::FindDyingJSObjects(nsTArray<nsXPCWrappedJS*>* dying)
|
||||
JSObject2WrappedJSMap::UpdateWeakPointersAfterGC(XPCJSRuntime *runtime)
|
||||
{
|
||||
for (Map::Range r = mTable.all(); !r.empty(); r.popFront()) {
|
||||
nsXPCWrappedJS* wrapper = r.front().value();
|
||||
// Check all wrappers and update their JSObject pointer if it has been
|
||||
// moved, or queue the wrapper for destruction if it is about to be
|
||||
// finalized.
|
||||
|
||||
nsTArray<nsXPCWrappedJS*> &dying = runtime->WrappedJSToReleaseArray();
|
||||
MOZ_ASSERT(dying.IsEmpty());
|
||||
|
||||
for (Map::Enum e(mTable); !e.empty(); e.popFront()) {
|
||||
nsXPCWrappedJS* wrapper = e.front().value();
|
||||
MOZ_ASSERT(wrapper, "found a null JS wrapper!");
|
||||
|
||||
// walk the wrapper chain and find any whose JSObject is to be finalized
|
||||
// Walk the wrapper chain and update all JSObjects.
|
||||
while (wrapper) {
|
||||
#ifdef DEBUG
|
||||
if (!wrapper->IsSubjectToFinalization()) {
|
||||
JSObject *obj = wrapper->GetJSObjectPreserveColor();
|
||||
JSObject *prior = obj;
|
||||
MOZ_ASSERT(!JS_IsAboutToBeFinalizedUnbarriered(&obj));
|
||||
// If a wrapper is not subject to finalization then it roots its
|
||||
// JS object. If so, then any necessary pointer update will
|
||||
// have already happened when it was marked.
|
||||
MOZ_ASSERT(obj == prior);
|
||||
}
|
||||
#endif
|
||||
if (wrapper->IsSubjectToFinalization() && wrapper->IsObjectAboutToBeFinalized())
|
||||
dying->AppendElement(wrapper);
|
||||
dying.AppendElement(wrapper);
|
||||
wrapper = wrapper->GetNextWrapper();
|
||||
}
|
||||
|
||||
// Remove or update the JSObject key in the table if necessary.
|
||||
JSObject *obj = e.front().key();
|
||||
JSObject *prior = obj;
|
||||
if (JS_IsAboutToBeFinalizedUnbarriered(&obj))
|
||||
e.removeFront();
|
||||
else if (obj != prior)
|
||||
e.rekeyFront(obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ public:
|
|||
r.front().value()->DebugDump(depth);
|
||||
}
|
||||
|
||||
void FindDyingJSObjects(nsTArray<nsXPCWrappedJS*>* dying);
|
||||
void UpdateWeakPointersAfterGC(XPCJSRuntime *runtime);
|
||||
|
||||
void ShutdownMarker();
|
||||
|
||||
|
|
|
@ -1334,6 +1334,15 @@ XPC_WN_Shared_Proto_Finalize(js::FreeOp *fop, JSObject *obj)
|
|||
p->JSProtoObjectFinalized(fop, obj);
|
||||
}
|
||||
|
||||
static void
|
||||
XPC_WN_Shared_Proto_ObjectMoved(JSObject *obj, const JSObject *old)
|
||||
{
|
||||
// This can be null if xpc shutdown has already happened
|
||||
XPCWrappedNativeProto* p = (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
|
||||
if (p)
|
||||
p->JSProtoObjectMoved(obj, old);
|
||||
}
|
||||
|
||||
static void
|
||||
XPC_WN_Shared_Proto_Trace(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
|
@ -1373,6 +1382,16 @@ XPC_WN_ModsAllowed_Proto_Resolve(JSContext *cx, HandleObject obj, HandleId id)
|
|||
enumFlag, nullptr);
|
||||
}
|
||||
|
||||
#define XPC_WN_SHARED_PROTO_CLASS_EXT \
|
||||
{ \
|
||||
nullptr, /* outerObject */ \
|
||||
nullptr, /* innerObject */ \
|
||||
nullptr, /* iteratorObject */ \
|
||||
false, /* isWrappedNative */ \
|
||||
nullptr, /* weakmapKeyDelegateOp */ \
|
||||
XPC_WN_Shared_Proto_ObjectMoved \
|
||||
}
|
||||
|
||||
const js::Class XPC_WN_ModsAllowed_WithCall_Proto_JSClass = {
|
||||
"XPC_WN_ModsAllowed_WithCall_Proto_JSClass", // name;
|
||||
WRAPPER_SLOTS, // flags;
|
||||
|
@ -1394,7 +1413,7 @@ const js::Class XPC_WN_ModsAllowed_WithCall_Proto_JSClass = {
|
|||
XPC_WN_Shared_Proto_Trace, // trace;
|
||||
|
||||
JS_NULL_CLASS_SPEC,
|
||||
JS_NULL_CLASS_EXT,
|
||||
XPC_WN_SHARED_PROTO_CLASS_EXT,
|
||||
XPC_WN_WithCall_ObjectOps
|
||||
};
|
||||
|
||||
|
@ -1419,7 +1438,7 @@ const js::Class XPC_WN_ModsAllowed_NoCall_Proto_JSClass = {
|
|||
XPC_WN_Shared_Proto_Trace, // trace;
|
||||
|
||||
JS_NULL_CLASS_SPEC,
|
||||
JS_NULL_CLASS_EXT,
|
||||
XPC_WN_SHARED_PROTO_CLASS_EXT,
|
||||
XPC_WN_NoCall_ObjectOps
|
||||
};
|
||||
|
||||
|
@ -1506,7 +1525,7 @@ const js::Class XPC_WN_NoMods_WithCall_Proto_JSClass = {
|
|||
XPC_WN_Shared_Proto_Trace, // trace;
|
||||
|
||||
JS_NULL_CLASS_SPEC,
|
||||
JS_NULL_CLASS_EXT,
|
||||
XPC_WN_SHARED_PROTO_CLASS_EXT,
|
||||
XPC_WN_WithCall_ObjectOps
|
||||
};
|
||||
|
||||
|
@ -1531,7 +1550,7 @@ const js::Class XPC_WN_NoMods_NoCall_Proto_JSClass = {
|
|||
XPC_WN_Shared_Proto_Trace, // trace;
|
||||
|
||||
JS_NULL_CLASS_SPEC,
|
||||
JS_NULL_CLASS_EXT,
|
||||
XPC_WN_SHARED_PROTO_CLASS_EXT,
|
||||
XPC_WN_NoCall_ObjectOps
|
||||
};
|
||||
|
||||
|
@ -1590,6 +1609,16 @@ XPC_WN_TearOff_Finalize(js::FreeOp *fop, JSObject *obj)
|
|||
p->JSObjectFinalized();
|
||||
}
|
||||
|
||||
static void
|
||||
XPC_WN_TearOff_ObjectMoved(JSObject *obj, const JSObject *old)
|
||||
{
|
||||
XPCWrappedNativeTearOff* p = (XPCWrappedNativeTearOff*)
|
||||
xpc_GetJSPrivate(obj);
|
||||
if (!p)
|
||||
return;
|
||||
p->JSObjectMoved(obj, old);
|
||||
}
|
||||
|
||||
const js::Class XPC_WN_Tearoff_JSClass = {
|
||||
"WrappedNative_TearOff", // name;
|
||||
WRAPPER_SLOTS, // flags;
|
||||
|
@ -1601,5 +1630,22 @@ const js::Class XPC_WN_Tearoff_JSClass = {
|
|||
XPC_WN_TearOff_Enumerate, // enumerate;
|
||||
XPC_WN_TearOff_Resolve, // resolve;
|
||||
XPC_WN_Shared_Convert, // convert;
|
||||
XPC_WN_TearOff_Finalize // finalize;
|
||||
XPC_WN_TearOff_Finalize, // finalize;
|
||||
|
||||
/* Optionally non-null members start here. */
|
||||
nullptr, // call
|
||||
nullptr, // construct
|
||||
nullptr, // hasInstance
|
||||
nullptr, // trace
|
||||
JS_NULL_CLASS_SPEC,
|
||||
|
||||
// ClassExtension
|
||||
{
|
||||
nullptr, // outerObject
|
||||
nullptr, // innerObject
|
||||
nullptr, // iteratorObject
|
||||
false, // isWrappedNative
|
||||
nullptr, // weakmapKeyDelegateOp
|
||||
XPC_WN_TearOff_ObjectMoved
|
||||
},
|
||||
};
|
||||
|
|
|
@ -142,6 +142,13 @@ XPCWrappedNativeProto::JSProtoObjectFinalized(js::FreeOp *fop, JSObject *obj)
|
|||
mJSProtoObject.finalize(js::CastToJSFreeOp(fop)->runtime());
|
||||
}
|
||||
|
||||
void
|
||||
XPCWrappedNativeProto::JSProtoObjectMoved(JSObject *obj, const JSObject *old)
|
||||
{
|
||||
MOZ_ASSERT(mJSProtoObject == old);
|
||||
mJSProtoObject.init(obj); // Update without triggering barriers.
|
||||
}
|
||||
|
||||
void
|
||||
XPCWrappedNativeProto::SystemIsBeingShutDown()
|
||||
{
|
||||
|
|
|
@ -487,10 +487,11 @@ XPCWrappedNativeScope::SuspectAllWrappers(XPCJSRuntime* rt,
|
|||
|
||||
// static
|
||||
void
|
||||
XPCWrappedNativeScope::StartFinalizationPhaseOfGC(JSFreeOp *fop, XPCJSRuntime* rt)
|
||||
XPCWrappedNativeScope::UpdateWeakPointersAfterGC(XPCJSRuntime* rt)
|
||||
{
|
||||
// We are in JSGC_MARK_END and JSGC_FINALIZE_END must always follow it
|
||||
// calling FinishedFinalizationPhaseOfGC and clearing gDyingScopes in
|
||||
// If this is called from the finalization callback in JSGC_MARK_END then
|
||||
// JSGC_FINALIZE_END must always follow it calling
|
||||
// FinishedFinalizationPhaseOfGC and clearing gDyingScopes in
|
||||
// KillDyingScopes.
|
||||
MOZ_ASSERT(!gDyingScopes, "JSGC_MARK_END without JSGC_FINALIZE_END");
|
||||
|
||||
|
@ -504,8 +505,11 @@ XPCWrappedNativeScope::StartFinalizationPhaseOfGC(JSFreeOp *fop, XPCJSRuntime* r
|
|||
|
||||
XPCWrappedNativeScope* next = cur->mNext;
|
||||
|
||||
// Check for finalization of the global object. Note that global
|
||||
// objects are never moved, so we don't need to handle updating the
|
||||
// object pointer here.
|
||||
if (cur->mGlobalJSObject && cur->mGlobalJSObject.isAboutToBeFinalized()) {
|
||||
cur->mGlobalJSObject.finalize(fop->runtime());
|
||||
cur->mGlobalJSObject.finalize(rt->Runtime());
|
||||
// Move this scope from the live list to the dying list.
|
||||
if (prev)
|
||||
prev->mNext = next;
|
||||
|
@ -515,19 +519,13 @@ XPCWrappedNativeScope::StartFinalizationPhaseOfGC(JSFreeOp *fop, XPCJSRuntime* r
|
|||
gDyingScopes = cur;
|
||||
cur = nullptr;
|
||||
}
|
||||
|
||||
if (cur)
|
||||
prev = cur;
|
||||
cur = next;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
XPCWrappedNativeScope::FinishedFinalizationPhaseOfGC()
|
||||
{
|
||||
KillDyingScopes();
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
WrappedNativeMarker(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
||||
uint32_t number_t, void *arg)
|
||||
|
|
|
@ -585,6 +585,7 @@ public:
|
|||
JSFinalizeStatus status,
|
||||
bool isCompartmentGC,
|
||||
void *data);
|
||||
static void MovingGCCallback(JSRuntime *rt, void *data);
|
||||
|
||||
inline void AddVariantRoot(XPCTraceableVariant* variant);
|
||||
inline void AddWrappedJSRoot(nsXPCWrappedJS* wrappedJS);
|
||||
|
@ -629,6 +630,8 @@ public:
|
|||
PRTime GetWatchdogTimestamp(WatchdogTimestampCategory aCategory);
|
||||
void OnAfterProcessNextEvent() { mSlowScriptCheckpoint = mozilla::TimeStamp(); }
|
||||
|
||||
nsTArray<nsXPCWrappedJS*>& WrappedJSToReleaseArray() { return mWrappedJSToReleaseArray; }
|
||||
|
||||
private:
|
||||
XPCJSRuntime(); // no implementation
|
||||
explicit XPCJSRuntime(nsXPConnect* aXPConnect);
|
||||
|
@ -1083,12 +1086,6 @@ public:
|
|||
static void
|
||||
SuspectAllWrappers(XPCJSRuntime* rt, nsCycleCollectionNoteRootCallback &cb);
|
||||
|
||||
static void
|
||||
StartFinalizationPhaseOfGC(JSFreeOp *fop, XPCJSRuntime* rt);
|
||||
|
||||
static void
|
||||
FinishedFinalizationPhaseOfGC();
|
||||
|
||||
static void
|
||||
MarkAllWrappedNativesAndProtos();
|
||||
|
||||
|
@ -1100,6 +1097,12 @@ public:
|
|||
static void
|
||||
SweepAllWrappedNativeTearOffs();
|
||||
|
||||
static void
|
||||
UpdateWeakPointersAfterGC(XPCJSRuntime* rt);
|
||||
|
||||
static void
|
||||
KillDyingScopes();
|
||||
|
||||
static void
|
||||
DebugDumpAllScopes(int16_t depth);
|
||||
|
||||
|
@ -1179,8 +1182,6 @@ public:
|
|||
protected:
|
||||
virtual ~XPCWrappedNativeScope();
|
||||
|
||||
static void KillDyingScopes();
|
||||
|
||||
XPCWrappedNativeScope(); // not implemented
|
||||
|
||||
private:
|
||||
|
@ -1850,6 +1851,7 @@ public:
|
|||
|
||||
bool CallPostCreatePrototype();
|
||||
void JSProtoObjectFinalized(js::FreeOp *fop, JSObject *obj);
|
||||
void JSProtoObjectMoved(JSObject *obj, const JSObject *old);
|
||||
|
||||
void SystemIsBeingShutDown();
|
||||
|
||||
|
@ -1944,6 +1946,7 @@ public:
|
|||
void SetJSObject(JSObject* JSObj);
|
||||
|
||||
void JSObjectFinalized() {SetJSObject(nullptr);}
|
||||
void JSObjectMoved(JSObject *obj, const JSObject *old);
|
||||
|
||||
XPCWrappedNativeTearOff()
|
||||
: mInterface(nullptr), mNative(nullptr), mJSObject(nullptr) {}
|
||||
|
|
Загрузка…
Ссылка в новой задаче