mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 650161 - Unify the finalization and moving GC callbacks into a weak pointer update callback r=terrence r=bholley
This commit is contained in:
parent
f93dcea4d5
commit
23f8fad496
@ -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();
|
||||
|
@ -21,7 +21,7 @@ class JavaScriptChild : public JavaScriptBase<PJavaScriptChild>
|
||||
virtual ~JavaScriptChild();
|
||||
|
||||
bool init();
|
||||
void finalize();
|
||||
void updateWeakPointers();
|
||||
|
||||
void drop(JSObject *obj);
|
||||
|
||||
|
@ -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 *
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -1207,7 +1207,7 @@ class JS_PUBLIC_API(ObjectPtr)
|
||||
IncrementalObjectBarrier(value);
|
||||
}
|
||||
|
||||
bool isAboutToBeFinalized();
|
||||
void updateWeakPointerAfterGC();
|
||||
|
||||
ObjectPtr &operator=(JSObject *obj) {
|
||||
IncrementalObjectBarrier(value);
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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. */
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;}
|
||||
|
Loading…
Reference in New Issue
Block a user