Bug 650161 - Unify the finalization and moving GC callbacks into a weak pointer update callback r=terrence r=bholley

This commit is contained in:
Jon Coppeard 2014-09-24 12:54:11 +01:00
parent f93dcea4d5
commit 23f8fad496
19 changed files with 159 additions and 132 deletions

View File

@ -21,17 +21,9 @@ using namespace mozilla::jsipc;
using mozilla::AutoSafeJSContext;
static void
FinalizeChild(JSFreeOp *fop, JSFinalizeStatus status, bool isCompartment, void *data)
UpdateChildWeakPointersAfterGC(JSRuntime *rt, void *data)
{
if (status == JSFINALIZE_GROUP_START) {
static_cast<JavaScriptChild *>(data)->finalize();
}
}
static void
FixupChildAfterMovingGC(JSRuntime *rt, void *data)
{
static_cast<JavaScriptChild *>(data)->fixupAfterMovingGC();
static_cast<JavaScriptChild *>(data)->updateWeakPointers();
}
JavaScriptChild::JavaScriptChild(JSRuntime *rt)
@ -42,8 +34,7 @@ JavaScriptChild::JavaScriptChild(JSRuntime *rt)
JavaScriptChild::~JavaScriptChild()
{
JS_RemoveFinalizeCallback(rt_, FinalizeChild);
JS_RemoveMovingGCCallback(rt_, FixupChildAfterMovingGC);
JS_RemoveWeakPointerCallback(rt_, UpdateChildWeakPointersAfterGC);
}
bool
@ -54,13 +45,12 @@ JavaScriptChild::init()
if (!WrapperAnswer::init())
return false;
JS_AddFinalizeCallback(rt_, FinalizeChild, this);
JS_AddMovingGCCallback(rt_, FixupChildAfterMovingGC, this);
JS_AddWeakPointerCallback(rt_, UpdateChildWeakPointersAfterGC, this);
return true;
}
void
JavaScriptChild::finalize()
JavaScriptChild::updateWeakPointers()
{
objects_.sweep();
objectIds_.sweep();

View File

@ -21,7 +21,7 @@ class JavaScriptChild : public JavaScriptBase<PJavaScriptChild>
virtual ~JavaScriptChild();
bool init();
void finalize();
void updateWeakPointers();
void drop(JSObject *obj);

View File

@ -27,12 +27,6 @@ TraceParent(JSTracer *trc, void *data)
static_cast<JavaScriptParent *>(data)->trace(trc);
}
static void
FixupParentAfterMovingGC(JSRuntime *rt, void *data)
{
static_cast<JavaScriptParent *>(data)->fixupAfterMovingGC();
}
JavaScriptParent::JavaScriptParent(JSRuntime *rt)
: JavaScriptShared(rt),
JavaScriptBase<PJavaScriptParent>(rt)
@ -42,7 +36,6 @@ JavaScriptParent::JavaScriptParent(JSRuntime *rt)
JavaScriptParent::~JavaScriptParent()
{
JS_RemoveExtraGCRootsTracer(rt_, TraceParent, this);
JS_RemoveMovingGCCallback(rt_, FixupParentAfterMovingGC);
}
bool
@ -52,15 +45,16 @@ JavaScriptParent::init()
return false;
JS_AddExtraGCRootsTracer(rt_, TraceParent, this);
JS_AddMovingGCCallback(rt_, FixupParentAfterMovingGC, this);
return true;
}
void
JavaScriptParent::trace(JSTracer *trc)
{
if (active())
if (active()) {
objects_.trace(trc);
objectIds_.trace(trc);
}
}
JSObject *

View File

@ -36,7 +36,6 @@ IdToObjectMap::trace(JSTracer *trc)
for (Table::Range r(table_.all()); !r.empty(); r.popFront()) {
DebugOnly<JSObject *> prior = r.front().value().get();
JS_CallObjectTracer(trc, &r.front().value(), "ipc-object");
MOZ_ASSERT(r.front().value() == prior);
}
}
@ -44,8 +43,9 @@ void
IdToObjectMap::sweep()
{
for (Table::Enum e(table_); !e.empty(); e.popFront()) {
DebugOnly<JSObject *> prior = e.front().value().get();
if (JS_IsAboutToBeFinalized(&e.front().value()))
JS::Heap<JSObject *> *objp = &e.front().value();
JS_UpdateWeakPointerAfterGC(objp);
if (!*objp)
e.removeFront();
}
}
@ -94,12 +94,24 @@ ObjectToIdMap::init()
return table_ && table_->init(32);
}
void
ObjectToIdMap::trace(JSTracer *trc)
{
for (Table::Enum e(*table_); !e.empty(); e.popFront()) {
JSObject *obj = e.front().key();
JS_CallUnbarrieredObjectTracer(trc, &obj, "ipc-object");
if (obj != e.front().key())
e.rekeyFront(obj);
}
}
void
ObjectToIdMap::sweep()
{
for (Table::Enum e(*table_); !e.empty(); e.popFront()) {
JSObject *obj = e.front().key();
if (JS_IsAboutToBeFinalizedUnbarriered(&obj))
JS_UpdateWeakPointerAfterGCUnbarriered(&obj);
if (!obj)
e.removeFront();
else if (obj != e.front().key())
e.rekeyFront(obj);
@ -568,9 +580,3 @@ JavaScriptShared::Wrap(JSContext *cx, HandleObject aObj, InfallibleTArray<CpowEn
return true;
}
void JavaScriptShared::fixupAfterMovingGC()
{
objects_.sweep();
cpows_.sweep();
objectIds_.sweep();
}

View File

@ -54,8 +54,6 @@ class IdToObjectMap
JSObject *find(ObjectId id);
void remove(ObjectId id);
void fixupAfterMovingGC();
private:
Table table_;
};
@ -71,14 +69,13 @@ class ObjectToIdMap
~ObjectToIdMap();
bool init();
void trace(JSTracer *trc);
void sweep();
bool add(JSContext *cx, JSObject *obj, ObjectId id);
ObjectId find(JSObject *obj);
void remove(JSObject *obj);
void fixupAfterMovingGC();
private:
static void keyMarkCallback(JSTracer *trc, JSObject *key, void *data);
@ -104,8 +101,6 @@ class JavaScriptShared
bool Unwrap(JSContext *cx, const InfallibleTArray<CpowEntry> &aCpows, JS::MutableHandleObject objp);
bool Wrap(JSContext *cx, JS::HandleObject aObj, InfallibleTArray<CpowEntry> *outCpows);
void fixupAfterMovingGC();
protected:
bool toVariant(JSContext *cx, JS::HandleValue from, JSVariant *to);
bool fromVariant(JSContext *cx, const JSVariant &from, JS::MutableHandleValue to);

View File

@ -31,7 +31,7 @@ OwnerOf(JSObject *obj)
}
ObjectId
WrapperOwner::idOf(JSObject *obj)
WrapperOwner::idOfUnchecked(JSObject *obj)
{
MOZ_ASSERT(IsCPOW(obj));
@ -39,12 +39,19 @@ WrapperOwner::idOf(JSObject *obj)
MOZ_ASSERT(v.isDouble());
ObjectId objId = BitwiseCast<uint64_t>(v.toDouble());
MOZ_ASSERT(findCPOWById(objId) == obj);
MOZ_ASSERT(objId);
return objId;
}
ObjectId
WrapperOwner::idOf(JSObject *obj)
{
ObjectId objId = idOfUnchecked(obj);
MOZ_ASSERT(findCPOWById(objId) == obj);
return objId;
}
class CPOWProxyHandler : public BaseProxyHandler
{
public:
@ -84,6 +91,7 @@ class CPOWProxyHandler : public BaseProxyHandler
JSContext *cx) const MOZ_OVERRIDE;
virtual const char* className(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
virtual void finalize(JSFreeOp *fop, JSObject *proxy) const MOZ_OVERRIDE;
virtual void objectMoved(JSObject *proxy, const JSObject *old) const MOZ_OVERRIDE;
virtual bool isCallable(JSObject *obj) const MOZ_OVERRIDE;
virtual bool isConstructor(JSObject *obj) const MOZ_OVERRIDE;
@ -648,6 +656,12 @@ CPOWProxyHandler::finalize(JSFreeOp *fop, JSObject *proxy) const
OwnerOf(proxy)->drop(proxy);
}
void
CPOWProxyHandler::objectMoved(JSObject *proxy, const JSObject *old) const
{
OwnerOf(proxy)->updatePointer(proxy, old);
}
bool
CPOWProxyHandler::isCallable(JSObject *obj) const
{
@ -678,6 +692,14 @@ WrapperOwner::drop(JSObject *obj)
decref();
}
void
WrapperOwner::updatePointer(JSObject *obj, const JSObject *old)
{
ObjectId objId = idOfUnchecked(obj);
MOZ_ASSERT(findCPOWById(objId) == old);
cpows_.add(objId, obj);
}
bool
WrapperOwner::init()
{

View File

@ -76,6 +76,7 @@ class WrapperOwner : public virtual JavaScriptShared
bool active() { return !inactive_; }
void drop(JSObject *obj);
void updatePointer(JSObject *obj, const JSObject *old);
virtual void ActorDestroy(ActorDestroyReason why);
@ -88,6 +89,8 @@ class WrapperOwner : public virtual JavaScriptShared
ObjectId idOf(JSObject *obj);
private:
ObjectId idOfUnchecked(JSObject *obj);
bool getPropertyNames(JSContext *cx, JS::HandleObject proxy, uint32_t flags,
JS::AutoIdVector &props);

View File

@ -1207,7 +1207,7 @@ class JS_PUBLIC_API(ObjectPtr)
IncrementalObjectBarrier(value);
}
bool isAboutToBeFinalized();
void updateWeakPointerAfterGC();
ObjectPtr &operator=(JSObject *obj) {
IncrementalObjectBarrier(value);

View File

@ -414,8 +414,8 @@ class GCRuntime
void setGCCallback(JSGCCallback callback, void *data);
bool addFinalizeCallback(JSFinalizeCallback callback, void *data);
void removeFinalizeCallback(JSFinalizeCallback func);
bool addMovingGCCallback(JSMovingGCCallback callback, void *data);
void removeMovingGCCallback(JSMovingGCCallback func);
bool addWeakPointerCallback(JSWeakPointerCallback callback, void *data);
void removeWeakPointerCallback(JSWeakPointerCallback func);
JS::GCSliceCallback setSliceCallback(JS::GCSliceCallback callback);
void setValidate(bool enable);
@ -550,7 +550,7 @@ class GCRuntime
#endif
void callFinalizeCallbacks(FreeOp *fop, JSFinalizeStatus status) const;
void callMovingGCCallbacks() const;
void callWeakPointerCallbacks() const;
public:
JSRuntime *rt;
@ -805,7 +805,7 @@ class GCRuntime
Callback<JSGCCallback> gcCallback;
CallbackVector<JSFinalizeCallback> finalizeCallbacks;
CallbackVector<JSMovingGCCallback> movingCallbacks;
CallbackVector<JSWeakPointerCallback> updateWeakPointerCallbacks;
/*
* Malloc counter to measure memory pressure for GC scheduling. It runs

View File

@ -1888,28 +1888,29 @@ JS_RemoveFinalizeCallback(JSRuntime *rt, JSFinalizeCallback cb)
}
JS_PUBLIC_API(bool)
JS_AddMovingGCCallback(JSRuntime *rt, JSMovingGCCallback cb, void *data)
JS_AddWeakPointerCallback(JSRuntime *rt, JSWeakPointerCallback cb, void *data)
{
AssertHeapIsIdle(rt);
return rt->gc.addMovingGCCallback(cb, data);
return rt->gc.addWeakPointerCallback(cb, data);
}
JS_PUBLIC_API(void)
JS_RemoveMovingGCCallback(JSRuntime *rt, JSMovingGCCallback cb)
JS_RemoveWeakPointerCallback(JSRuntime *rt, JSWeakPointerCallback cb)
{
rt->gc.removeMovingGCCallback(cb);
rt->gc.removeWeakPointerCallback(cb);
}
JS_PUBLIC_API(bool)
JS_IsAboutToBeFinalized(JS::Heap<JSObject *> *objp)
JS_PUBLIC_API(void)
JS_UpdateWeakPointerAfterGC(JS::Heap<JSObject *> *objp)
{
return IsObjectAboutToBeFinalized(objp->unsafeGet());
JS_UpdateWeakPointerAfterGCUnbarriered(objp->unsafeGet());
}
JS_PUBLIC_API(bool)
JS_IsAboutToBeFinalizedUnbarriered(JSObject **objp)
JS_PUBLIC_API(void)
JS_UpdateWeakPointerAfterGCUnbarriered(JSObject **objp)
{
return IsObjectAboutToBeFinalized(objp);
if (IsObjectAboutToBeFinalized(objp))
*objp = nullptr;
}
JS_PUBLIC_API(void)

View File

@ -690,7 +690,7 @@ typedef void
(* JSFinalizeCallback)(JSFreeOp *fop, JSFinalizeStatus status, bool isCompartment, void *data);
typedef void
(* JSMovingGCCallback)(JSRuntime *rt, void *data);
(* JSWeakPointerCallback)(JSRuntime *rt, void *data);
typedef bool
(* JSInterruptCallback)(JSContext *cx);
@ -2038,12 +2038,6 @@ JS_AddFinalizeCallback(JSRuntime *rt, JSFinalizeCallback cb, void *data);
extern JS_PUBLIC_API(void)
JS_RemoveFinalizeCallback(JSRuntime *rt, JSFinalizeCallback cb);
extern JS_PUBLIC_API(bool)
JS_AddMovingGCCallback(JSRuntime *rt, JSMovingGCCallback cb, void *data);
extern JS_PUBLIC_API(void)
JS_RemoveMovingGCCallback(JSRuntime *rt, JSMovingGCCallback cb);
extern JS_PUBLIC_API(bool)
JS_IsGCMarkingTracer(JSTracer *trc);
@ -2054,26 +2048,41 @@ JS_IsMarkingGray(JSTracer *trc);
#endif
/*
* JS_IsAboutToBeFinalized checks if the given object is going to be finalized
* at the end of the current GC. When called outside of the context of a GC,
* this function will return false. Typically this function is used on weak
* references, where the reference should be nulled out or destroyed if the
* given object is about to be finalized.
* Weak pointers and garbage collection
*
* Weak pointers are by their nature not marked as part of garbage collection,
* but they may need to be updated in two cases after a GC:
*
* 1) Their referent was found not to be live and is about to be finalized
* 2) Their referent has been moved by a compacting GC
*
* To handle this, any part of the system that maintain weak pointers to
* JavaScript GC things must register a callback with
* JS_(Add,Remove)WeakPointerCallback(). This callback must then call
* JS_UpdateWeakPointerAfterGC() on all weak pointers it knows about.
*
* The argument to JS_UpdateWeakPointerAfterGC() is an in-out param. If the
* referent is about to be finalized the pointer will be set to null. If the
* referent has been moved then the pointer will be updated to point to the new
* location.
*
* The argument to JS_IsAboutToBeFinalized is an in-out param: when the
* function returns false, the object being referenced is still alive, but the
* garbage collector might have moved it. In this case, the reference passed
* to JS_IsAboutToBeFinalized will be updated to the object's new location.
* Callers of this method are responsible for updating any state that is
* dependent on the object's address. For example, if the object's address is
* used as a key in a hashtable, then the object must be removed and
* re-inserted with the correct hash.
*/
extern JS_PUBLIC_API(bool)
JS_IsAboutToBeFinalized(JS::Heap<JSObject *> *objp);
extern JS_PUBLIC_API(bool)
JS_IsAboutToBeFinalizedUnbarriered(JSObject **objp);
JS_AddWeakPointerCallback(JSRuntime *rt, JSWeakPointerCallback cb, void *data);
extern JS_PUBLIC_API(void)
JS_RemoveWeakPointerCallback(JSRuntime *rt, JSWeakPointerCallback cb);
extern JS_PUBLIC_API(void)
JS_UpdateWeakPointerAfterGC(JS::Heap<JSObject *> *objp);
extern JS_PUBLIC_API(void)
JS_UpdateWeakPointerAfterGCUnbarriered(JSObject **objp);
typedef enum JSGCParamKey {
/* Maximum nominal heap before last ditch GC. */

View File

@ -1235,10 +1235,11 @@ js::GetAnyCompartmentInZone(JS::Zone *zone)
return comp.get();
}
bool
JS::ObjectPtr::isAboutToBeFinalized()
void
JS::ObjectPtr::updateWeakPointerAfterGC()
{
return JS_IsAboutToBeFinalized(&value);
if (js::gc::IsObjectAboutToBeFinalized(value.unsafeGet()))
value = nullptr;
}
void

View File

@ -1623,29 +1623,29 @@ GCRuntime::callFinalizeCallbacks(FreeOp *fop, JSFinalizeStatus status) const
}
bool
GCRuntime::addMovingGCCallback(JSMovingGCCallback callback, void *data)
GCRuntime::addWeakPointerCallback(JSWeakPointerCallback callback, void *data)
{
return movingCallbacks.append(Callback<JSMovingGCCallback>(callback, data));
return updateWeakPointerCallbacks.append(Callback<JSWeakPointerCallback>(callback, data));
}
void
GCRuntime::removeMovingGCCallback(JSMovingGCCallback callback)
GCRuntime::removeWeakPointerCallback(JSWeakPointerCallback callback)
{
for (Callback<JSMovingGCCallback> *p = movingCallbacks.begin();
p < movingCallbacks.end(); p++)
for (Callback<JSWeakPointerCallback> *p = updateWeakPointerCallbacks.begin();
p < updateWeakPointerCallbacks.end(); p++)
{
if (p->op == callback) {
movingCallbacks.erase(p);
updateWeakPointerCallbacks.erase(p);
break;
}
}
}
void
GCRuntime::callMovingGCCallbacks() const
GCRuntime::callWeakPointerCallbacks() const
{
for (const Callback<JSMovingGCCallback> *p = movingCallbacks.begin();
p < movingCallbacks.end(); p++)
for (const Callback<JSWeakPointerCallback> *p = updateWeakPointerCallbacks.begin();
p < updateWeakPointerCallbacks.end(); p++)
{
p->op(rt, p->data);
}
@ -2461,7 +2461,7 @@ GCRuntime::updatePointersToRelocatedCells()
MovingTracer::Sweep(&trc);
// Call callbacks to get the rest of the system to fixup other untraced pointers.
callMovingGCCallbacks();
callWeakPointerCallbacks();
}
void
@ -4636,6 +4636,7 @@ GCRuntime::beginSweepingZoneGroup()
{
gcstats::AutoPhase ap(stats, gcstats::PHASE_FINALIZE_START);
callFinalizeCallbacks(&fop, JSFINALIZE_GROUP_START);
callWeakPointerCallbacks();
}
if (sweepingAtoms) {

View File

@ -789,17 +789,6 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp *fop,
MOZ_ASSERT(!self->mGCIsRunning, "bad state");
self->mGCIsRunning = true;
// 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->UpdateWeakPointersAfterGC(self);
// Find dying scopes.
XPCWrappedNativeScope::UpdateWeakPointersAfterGC(self);
self->mDoingFinalization = true;
break;
}
@ -969,14 +958,14 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp *fop,
}
/* static */ void
XPCJSRuntime::MovingGCCallback(JSRuntime *rt, void *data)
XPCJSRuntime::WeakPointerCallback(JSRuntime *rt, void *data)
{
// Called to fixup any weak GC thing pointers that may have been moved.
// Called to remove any weak pointers to GC things that are about to be
// finalized and fixup any pointers that may have been moved.
XPCJSRuntime *self = static_cast<XPCJSRuntime *>(data);
self->mWrappedJSMap->UpdateWeakPointersAfterGC(self);
MOZ_ASSERT(self->WrappedJSToReleaseArray().IsEmpty());
XPCWrappedNativeScope::UpdateWeakPointersAfterGC(self);
}
@ -1547,7 +1536,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);
JS_RemoveWeakPointerCallback(Runtime(), WeakPointerCallback);
// Clear any pending exception. It might be an XPCWrappedJS, and if we try
// to destroy it later we will crash.
@ -3246,7 +3235,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_AddWeakPointerCallback(runtime, WeakPointerCallback, this);
JS_SetWrapObjectCallbacks(runtime, &WrapObjectCallbacks);
js::SetPreserveWrapperCallback(runtime, PreserveWrapper);
#ifdef MOZ_CRASHREPORTER

View File

@ -88,8 +88,11 @@ void
JSObject2WrappedJSMap::UpdateWeakPointersAfterGC(XPCJSRuntime *runtime)
{
// 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.
// moved, or if it is about to be finalized queue the wrapper for
// destruction by adding it to an array held by the runtime.
// 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.
nsTArray<nsXPCWrappedJS*> &dying = runtime->WrappedJSToReleaseArray();
MOZ_ASSERT(dying.IsEmpty());
@ -102,24 +105,29 @@ JSObject2WrappedJSMap::UpdateWeakPointersAfterGC(XPCJSRuntime *runtime)
while (wrapper) {
#ifdef DEBUG
if (!wrapper->IsSubjectToFinalization()) {
// If a wrapper is not subject to finalization then it roots its
// JS object. If so, then it will not be about to be finalized
// and any necessary pointer update will have already happened
// when it was marked.
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.
JS_UpdateWeakPointerAfterGCUnbarriered(&obj);
MOZ_ASSERT(obj == prior);
}
#endif
if (wrapper->IsSubjectToFinalization() && wrapper->IsObjectAboutToBeFinalized())
dying.AppendElement(wrapper);
if (wrapper->IsSubjectToFinalization()) {
wrapper->UpdateObjectPointerAfterGC();
if (!wrapper->GetJSObjectPreserveColor())
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))
JS_UpdateWeakPointerAfterGCUnbarriered(&obj);
if (!obj)
e.removeFront();
else if (obj != prior)
e.rekeyFront(obj);

View File

@ -657,11 +657,14 @@ public:
void Sweep() {
for (Map::Enum e(mTable); !e.empty(); e.popFront()) {
JSObject *updated = e.front().key();
if (JS_IsAboutToBeFinalizedUnbarriered(&updated) || JS_IsAboutToBeFinalized(&e.front().value()))
JSObject *key = e.front().key();
JS::Heap<JSObject *> *valuep = &e.front().value();
JS_UpdateWeakPointerAfterGCUnbarriered(&key);
JS_UpdateWeakPointerAfterGC(valuep);
if (!key || !*valuep)
e.removeFront();
else if (updated != e.front().key())
e.rekeyFront(updated);
else if (key != e.front().key())
e.rekeyFront(key);
}
}

View File

@ -940,8 +940,11 @@ XPCWrappedNative::FlatJSObjectFinalized()
for (int i = XPC_WRAPPED_NATIVE_TEAROFFS_PER_CHUNK-1; i >= 0; i--, to++) {
JSObject* jso = to->GetJSObjectPreserveColor();
if (jso) {
MOZ_ASSERT(JS_IsAboutToBeFinalizedUnbarriered(&jso));
JS_SetPrivate(jso, nullptr);
#ifdef DEBUG
JS_UpdateWeakPointerAfterGCUnbarriered(&jso);
MOZ_ASSERT(!jso);
#endif
to->JSObjectFinalized();
}

View File

@ -508,16 +508,18 @@ XPCWrappedNativeScope::UpdateWeakPointersAfterGC(XPCJSRuntime* rt)
// 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(rt->Runtime());
// Move this scope from the live list to the dying list.
if (prev)
prev->mNext = next;
else
gScopes = next;
cur->mNext = gDyingScopes;
gDyingScopes = cur;
cur = nullptr;
if (cur->mGlobalJSObject) {
cur->mGlobalJSObject.updateWeakPointerAfterGC();
if (!cur->mGlobalJSObject) {
// Move this scope from the live list to the dying list.
if (prev)
prev->mNext = next;
else
gScopes = next;
cur->mNext = gDyingScopes;
gDyingScopes = cur;
cur = nullptr;
}
}
if (cur)

View File

@ -585,7 +585,7 @@ public:
JSFinalizeStatus status,
bool isCompartmentGC,
void *data);
static void MovingGCCallback(JSRuntime *rt, void *data);
static void WeakPointerCallback(JSRuntime *rt, void *data);
inline void AddVariantRoot(XPCTraceableVariant* variant);
inline void AddWrappedJSRoot(nsXPCWrappedJS* wrappedJS);
@ -2471,7 +2471,7 @@ public:
// to find non-rooting wrappers for dying JS objects. See the top of
// XPCWrappedJS.cpp for more details.
bool IsSubjectToFinalization() const {return IsValid() && mRefCnt == 1;}
bool IsObjectAboutToBeFinalized() {return JS_IsAboutToBeFinalized(&mJSObj);}
void UpdateObjectPointerAfterGC() {JS_UpdateWeakPointerAfterGC(&mJSObj);}
bool IsAggregatedToNative() const {return mRoot->mOuter != nullptr;}
nsISupports* GetAggregatedNativeObject() const {return mRoot->mOuter;}