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;
|
using mozilla::AutoSafeJSContext;
|
||||||
|
|
||||||
static void
|
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)->updateWeakPointers();
|
||||||
static_cast<JavaScriptChild *>(data)->finalize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
FixupChildAfterMovingGC(JSRuntime *rt, void *data)
|
|
||||||
{
|
|
||||||
static_cast<JavaScriptChild *>(data)->fixupAfterMovingGC();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JavaScriptChild::JavaScriptChild(JSRuntime *rt)
|
JavaScriptChild::JavaScriptChild(JSRuntime *rt)
|
||||||
@ -42,8 +34,7 @@ JavaScriptChild::JavaScriptChild(JSRuntime *rt)
|
|||||||
|
|
||||||
JavaScriptChild::~JavaScriptChild()
|
JavaScriptChild::~JavaScriptChild()
|
||||||
{
|
{
|
||||||
JS_RemoveFinalizeCallback(rt_, FinalizeChild);
|
JS_RemoveWeakPointerCallback(rt_, UpdateChildWeakPointersAfterGC);
|
||||||
JS_RemoveMovingGCCallback(rt_, FixupChildAfterMovingGC);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -54,13 +45,12 @@ JavaScriptChild::init()
|
|||||||
if (!WrapperAnswer::init())
|
if (!WrapperAnswer::init())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
JS_AddFinalizeCallback(rt_, FinalizeChild, this);
|
JS_AddWeakPointerCallback(rt_, UpdateChildWeakPointersAfterGC, this);
|
||||||
JS_AddMovingGCCallback(rt_, FixupChildAfterMovingGC, this);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
JavaScriptChild::finalize()
|
JavaScriptChild::updateWeakPointers()
|
||||||
{
|
{
|
||||||
objects_.sweep();
|
objects_.sweep();
|
||||||
objectIds_.sweep();
|
objectIds_.sweep();
|
||||||
|
@ -21,7 +21,7 @@ class JavaScriptChild : public JavaScriptBase<PJavaScriptChild>
|
|||||||
virtual ~JavaScriptChild();
|
virtual ~JavaScriptChild();
|
||||||
|
|
||||||
bool init();
|
bool init();
|
||||||
void finalize();
|
void updateWeakPointers();
|
||||||
|
|
||||||
void drop(JSObject *obj);
|
void drop(JSObject *obj);
|
||||||
|
|
||||||
|
@ -27,12 +27,6 @@ TraceParent(JSTracer *trc, void *data)
|
|||||||
static_cast<JavaScriptParent *>(data)->trace(trc);
|
static_cast<JavaScriptParent *>(data)->trace(trc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
FixupParentAfterMovingGC(JSRuntime *rt, void *data)
|
|
||||||
{
|
|
||||||
static_cast<JavaScriptParent *>(data)->fixupAfterMovingGC();
|
|
||||||
}
|
|
||||||
|
|
||||||
JavaScriptParent::JavaScriptParent(JSRuntime *rt)
|
JavaScriptParent::JavaScriptParent(JSRuntime *rt)
|
||||||
: JavaScriptShared(rt),
|
: JavaScriptShared(rt),
|
||||||
JavaScriptBase<PJavaScriptParent>(rt)
|
JavaScriptBase<PJavaScriptParent>(rt)
|
||||||
@ -42,7 +36,6 @@ JavaScriptParent::JavaScriptParent(JSRuntime *rt)
|
|||||||
JavaScriptParent::~JavaScriptParent()
|
JavaScriptParent::~JavaScriptParent()
|
||||||
{
|
{
|
||||||
JS_RemoveExtraGCRootsTracer(rt_, TraceParent, this);
|
JS_RemoveExtraGCRootsTracer(rt_, TraceParent, this);
|
||||||
JS_RemoveMovingGCCallback(rt_, FixupParentAfterMovingGC);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -52,15 +45,16 @@ JavaScriptParent::init()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
JS_AddExtraGCRootsTracer(rt_, TraceParent, this);
|
JS_AddExtraGCRootsTracer(rt_, TraceParent, this);
|
||||||
JS_AddMovingGCCallback(rt_, FixupParentAfterMovingGC, this);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
JavaScriptParent::trace(JSTracer *trc)
|
JavaScriptParent::trace(JSTracer *trc)
|
||||||
{
|
{
|
||||||
if (active())
|
if (active()) {
|
||||||
objects_.trace(trc);
|
objects_.trace(trc);
|
||||||
|
objectIds_.trace(trc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject *
|
JSObject *
|
||||||
|
@ -36,7 +36,6 @@ IdToObjectMap::trace(JSTracer *trc)
|
|||||||
for (Table::Range r(table_.all()); !r.empty(); r.popFront()) {
|
for (Table::Range r(table_.all()); !r.empty(); r.popFront()) {
|
||||||
DebugOnly<JSObject *> prior = r.front().value().get();
|
DebugOnly<JSObject *> prior = r.front().value().get();
|
||||||
JS_CallObjectTracer(trc, &r.front().value(), "ipc-object");
|
JS_CallObjectTracer(trc, &r.front().value(), "ipc-object");
|
||||||
MOZ_ASSERT(r.front().value() == prior);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,8 +43,9 @@ void
|
|||||||
IdToObjectMap::sweep()
|
IdToObjectMap::sweep()
|
||||||
{
|
{
|
||||||
for (Table::Enum e(table_); !e.empty(); e.popFront()) {
|
for (Table::Enum e(table_); !e.empty(); e.popFront()) {
|
||||||
DebugOnly<JSObject *> prior = e.front().value().get();
|
JS::Heap<JSObject *> *objp = &e.front().value();
|
||||||
if (JS_IsAboutToBeFinalized(&e.front().value()))
|
JS_UpdateWeakPointerAfterGC(objp);
|
||||||
|
if (!*objp)
|
||||||
e.removeFront();
|
e.removeFront();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,12 +94,24 @@ ObjectToIdMap::init()
|
|||||||
return table_ && table_->init(32);
|
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
|
void
|
||||||
ObjectToIdMap::sweep()
|
ObjectToIdMap::sweep()
|
||||||
{
|
{
|
||||||
for (Table::Enum e(*table_); !e.empty(); e.popFront()) {
|
for (Table::Enum e(*table_); !e.empty(); e.popFront()) {
|
||||||
JSObject *obj = e.front().key();
|
JSObject *obj = e.front().key();
|
||||||
if (JS_IsAboutToBeFinalizedUnbarriered(&obj))
|
JS_UpdateWeakPointerAfterGCUnbarriered(&obj);
|
||||||
|
if (!obj)
|
||||||
e.removeFront();
|
e.removeFront();
|
||||||
else if (obj != e.front().key())
|
else if (obj != e.front().key())
|
||||||
e.rekeyFront(obj);
|
e.rekeyFront(obj);
|
||||||
@ -568,9 +580,3 @@ JavaScriptShared::Wrap(JSContext *cx, HandleObject aObj, InfallibleTArray<CpowEn
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
void JavaScriptShared::fixupAfterMovingGC()
|
|
||||||
{
|
|
||||||
objects_.sweep();
|
|
||||||
cpows_.sweep();
|
|
||||||
objectIds_.sweep();
|
|
||||||
}
|
|
||||||
|
@ -54,8 +54,6 @@ class IdToObjectMap
|
|||||||
JSObject *find(ObjectId id);
|
JSObject *find(ObjectId id);
|
||||||
void remove(ObjectId id);
|
void remove(ObjectId id);
|
||||||
|
|
||||||
void fixupAfterMovingGC();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Table table_;
|
Table table_;
|
||||||
};
|
};
|
||||||
@ -71,14 +69,13 @@ class ObjectToIdMap
|
|||||||
~ObjectToIdMap();
|
~ObjectToIdMap();
|
||||||
|
|
||||||
bool init();
|
bool init();
|
||||||
|
void trace(JSTracer *trc);
|
||||||
void sweep();
|
void sweep();
|
||||||
|
|
||||||
bool add(JSContext *cx, JSObject *obj, ObjectId id);
|
bool add(JSContext *cx, JSObject *obj, ObjectId id);
|
||||||
ObjectId find(JSObject *obj);
|
ObjectId find(JSObject *obj);
|
||||||
void remove(JSObject *obj);
|
void remove(JSObject *obj);
|
||||||
|
|
||||||
void fixupAfterMovingGC();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void keyMarkCallback(JSTracer *trc, JSObject *key, void *data);
|
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 Unwrap(JSContext *cx, const InfallibleTArray<CpowEntry> &aCpows, JS::MutableHandleObject objp);
|
||||||
bool Wrap(JSContext *cx, JS::HandleObject aObj, InfallibleTArray<CpowEntry> *outCpows);
|
bool Wrap(JSContext *cx, JS::HandleObject aObj, InfallibleTArray<CpowEntry> *outCpows);
|
||||||
|
|
||||||
void fixupAfterMovingGC();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool toVariant(JSContext *cx, JS::HandleValue from, JSVariant *to);
|
bool toVariant(JSContext *cx, JS::HandleValue from, JSVariant *to);
|
||||||
bool fromVariant(JSContext *cx, const JSVariant &from, JS::MutableHandleValue to);
|
bool fromVariant(JSContext *cx, const JSVariant &from, JS::MutableHandleValue to);
|
||||||
|
@ -31,7 +31,7 @@ OwnerOf(JSObject *obj)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ObjectId
|
ObjectId
|
||||||
WrapperOwner::idOf(JSObject *obj)
|
WrapperOwner::idOfUnchecked(JSObject *obj)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(IsCPOW(obj));
|
MOZ_ASSERT(IsCPOW(obj));
|
||||||
|
|
||||||
@ -39,12 +39,19 @@ WrapperOwner::idOf(JSObject *obj)
|
|||||||
MOZ_ASSERT(v.isDouble());
|
MOZ_ASSERT(v.isDouble());
|
||||||
|
|
||||||
ObjectId objId = BitwiseCast<uint64_t>(v.toDouble());
|
ObjectId objId = BitwiseCast<uint64_t>(v.toDouble());
|
||||||
MOZ_ASSERT(findCPOWById(objId) == obj);
|
|
||||||
MOZ_ASSERT(objId);
|
MOZ_ASSERT(objId);
|
||||||
|
|
||||||
return objId;
|
return objId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ObjectId
|
||||||
|
WrapperOwner::idOf(JSObject *obj)
|
||||||
|
{
|
||||||
|
ObjectId objId = idOfUnchecked(obj);
|
||||||
|
MOZ_ASSERT(findCPOWById(objId) == obj);
|
||||||
|
return objId;
|
||||||
|
}
|
||||||
|
|
||||||
class CPOWProxyHandler : public BaseProxyHandler
|
class CPOWProxyHandler : public BaseProxyHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -84,6 +91,7 @@ class CPOWProxyHandler : public BaseProxyHandler
|
|||||||
JSContext *cx) const MOZ_OVERRIDE;
|
JSContext *cx) const MOZ_OVERRIDE;
|
||||||
virtual const char* className(JSContext *cx, HandleObject proxy) 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 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 isCallable(JSObject *obj) const MOZ_OVERRIDE;
|
||||||
virtual bool isConstructor(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);
|
OwnerOf(proxy)->drop(proxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPOWProxyHandler::objectMoved(JSObject *proxy, const JSObject *old) const
|
||||||
|
{
|
||||||
|
OwnerOf(proxy)->updatePointer(proxy, old);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CPOWProxyHandler::isCallable(JSObject *obj) const
|
CPOWProxyHandler::isCallable(JSObject *obj) const
|
||||||
{
|
{
|
||||||
@ -678,6 +692,14 @@ WrapperOwner::drop(JSObject *obj)
|
|||||||
decref();
|
decref();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
WrapperOwner::updatePointer(JSObject *obj, const JSObject *old)
|
||||||
|
{
|
||||||
|
ObjectId objId = idOfUnchecked(obj);
|
||||||
|
MOZ_ASSERT(findCPOWById(objId) == old);
|
||||||
|
cpows_.add(objId, obj);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
WrapperOwner::init()
|
WrapperOwner::init()
|
||||||
{
|
{
|
||||||
|
@ -76,6 +76,7 @@ class WrapperOwner : public virtual JavaScriptShared
|
|||||||
bool active() { return !inactive_; }
|
bool active() { return !inactive_; }
|
||||||
|
|
||||||
void drop(JSObject *obj);
|
void drop(JSObject *obj);
|
||||||
|
void updatePointer(JSObject *obj, const JSObject *old);
|
||||||
|
|
||||||
virtual void ActorDestroy(ActorDestroyReason why);
|
virtual void ActorDestroy(ActorDestroyReason why);
|
||||||
|
|
||||||
@ -88,6 +89,8 @@ class WrapperOwner : public virtual JavaScriptShared
|
|||||||
ObjectId idOf(JSObject *obj);
|
ObjectId idOf(JSObject *obj);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
ObjectId idOfUnchecked(JSObject *obj);
|
||||||
|
|
||||||
bool getPropertyNames(JSContext *cx, JS::HandleObject proxy, uint32_t flags,
|
bool getPropertyNames(JSContext *cx, JS::HandleObject proxy, uint32_t flags,
|
||||||
JS::AutoIdVector &props);
|
JS::AutoIdVector &props);
|
||||||
|
|
||||||
|
@ -1207,7 +1207,7 @@ class JS_PUBLIC_API(ObjectPtr)
|
|||||||
IncrementalObjectBarrier(value);
|
IncrementalObjectBarrier(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isAboutToBeFinalized();
|
void updateWeakPointerAfterGC();
|
||||||
|
|
||||||
ObjectPtr &operator=(JSObject *obj) {
|
ObjectPtr &operator=(JSObject *obj) {
|
||||||
IncrementalObjectBarrier(value);
|
IncrementalObjectBarrier(value);
|
||||||
|
@ -414,8 +414,8 @@ class GCRuntime
|
|||||||
void setGCCallback(JSGCCallback callback, void *data);
|
void setGCCallback(JSGCCallback callback, void *data);
|
||||||
bool addFinalizeCallback(JSFinalizeCallback callback, void *data);
|
bool addFinalizeCallback(JSFinalizeCallback callback, void *data);
|
||||||
void removeFinalizeCallback(JSFinalizeCallback func);
|
void removeFinalizeCallback(JSFinalizeCallback func);
|
||||||
bool addMovingGCCallback(JSMovingGCCallback callback, void *data);
|
bool addWeakPointerCallback(JSWeakPointerCallback callback, void *data);
|
||||||
void removeMovingGCCallback(JSMovingGCCallback func);
|
void removeWeakPointerCallback(JSWeakPointerCallback func);
|
||||||
JS::GCSliceCallback setSliceCallback(JS::GCSliceCallback callback);
|
JS::GCSliceCallback setSliceCallback(JS::GCSliceCallback callback);
|
||||||
|
|
||||||
void setValidate(bool enable);
|
void setValidate(bool enable);
|
||||||
@ -550,7 +550,7 @@ class GCRuntime
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void callFinalizeCallbacks(FreeOp *fop, JSFinalizeStatus status) const;
|
void callFinalizeCallbacks(FreeOp *fop, JSFinalizeStatus status) const;
|
||||||
void callMovingGCCallbacks() const;
|
void callWeakPointerCallbacks() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
JSRuntime *rt;
|
JSRuntime *rt;
|
||||||
@ -805,7 +805,7 @@ class GCRuntime
|
|||||||
|
|
||||||
Callback<JSGCCallback> gcCallback;
|
Callback<JSGCCallback> gcCallback;
|
||||||
CallbackVector<JSFinalizeCallback> finalizeCallbacks;
|
CallbackVector<JSFinalizeCallback> finalizeCallbacks;
|
||||||
CallbackVector<JSMovingGCCallback> movingCallbacks;
|
CallbackVector<JSWeakPointerCallback> updateWeakPointerCallbacks;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Malloc counter to measure memory pressure for GC scheduling. It runs
|
* 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_PUBLIC_API(bool)
|
||||||
JS_AddMovingGCCallback(JSRuntime *rt, JSMovingGCCallback cb, void *data)
|
JS_AddWeakPointerCallback(JSRuntime *rt, JSWeakPointerCallback cb, void *data)
|
||||||
{
|
{
|
||||||
AssertHeapIsIdle(rt);
|
AssertHeapIsIdle(rt);
|
||||||
return rt->gc.addMovingGCCallback(cb, data);
|
return rt->gc.addWeakPointerCallback(cb, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(void)
|
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_PUBLIC_API(void)
|
||||||
JS_IsAboutToBeFinalized(JS::Heap<JSObject *> *objp)
|
JS_UpdateWeakPointerAfterGC(JS::Heap<JSObject *> *objp)
|
||||||
{
|
{
|
||||||
return IsObjectAboutToBeFinalized(objp->unsafeGet());
|
JS_UpdateWeakPointerAfterGCUnbarriered(objp->unsafeGet());
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(bool)
|
JS_PUBLIC_API(void)
|
||||||
JS_IsAboutToBeFinalizedUnbarriered(JSObject **objp)
|
JS_UpdateWeakPointerAfterGCUnbarriered(JSObject **objp)
|
||||||
{
|
{
|
||||||
return IsObjectAboutToBeFinalized(objp);
|
if (IsObjectAboutToBeFinalized(objp))
|
||||||
|
*objp = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(void)
|
JS_PUBLIC_API(void)
|
||||||
|
@ -690,7 +690,7 @@ typedef void
|
|||||||
(* JSFinalizeCallback)(JSFreeOp *fop, JSFinalizeStatus status, bool isCompartment, void *data);
|
(* JSFinalizeCallback)(JSFreeOp *fop, JSFinalizeStatus status, bool isCompartment, void *data);
|
||||||
|
|
||||||
typedef void
|
typedef void
|
||||||
(* JSMovingGCCallback)(JSRuntime *rt, void *data);
|
(* JSWeakPointerCallback)(JSRuntime *rt, void *data);
|
||||||
|
|
||||||
typedef bool
|
typedef bool
|
||||||
(* JSInterruptCallback)(JSContext *cx);
|
(* JSInterruptCallback)(JSContext *cx);
|
||||||
@ -2038,12 +2038,6 @@ JS_AddFinalizeCallback(JSRuntime *rt, JSFinalizeCallback cb, void *data);
|
|||||||
extern JS_PUBLIC_API(void)
|
extern JS_PUBLIC_API(void)
|
||||||
JS_RemoveFinalizeCallback(JSRuntime *rt, JSFinalizeCallback cb);
|
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)
|
extern JS_PUBLIC_API(bool)
|
||||||
JS_IsGCMarkingTracer(JSTracer *trc);
|
JS_IsGCMarkingTracer(JSTracer *trc);
|
||||||
|
|
||||||
@ -2054,26 +2048,41 @@ JS_IsMarkingGray(JSTracer *trc);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* JS_IsAboutToBeFinalized checks if the given object is going to be finalized
|
* Weak pointers and garbage collection
|
||||||
* 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
|
* Weak pointers are by their nature not marked as part of garbage collection,
|
||||||
* references, where the reference should be nulled out or destroyed if the
|
* but they may need to be updated in two cases after a GC:
|
||||||
* given object is about to be finalized.
|
*
|
||||||
|
* 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
|
* 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
|
* 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
|
* used as a key in a hashtable, then the object must be removed and
|
||||||
* re-inserted with the correct hash.
|
* re-inserted with the correct hash.
|
||||||
*/
|
*/
|
||||||
extern JS_PUBLIC_API(bool)
|
|
||||||
JS_IsAboutToBeFinalized(JS::Heap<JSObject *> *objp);
|
|
||||||
|
|
||||||
extern JS_PUBLIC_API(bool)
|
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 {
|
typedef enum JSGCParamKey {
|
||||||
/* Maximum nominal heap before last ditch GC. */
|
/* Maximum nominal heap before last ditch GC. */
|
||||||
|
@ -1235,10 +1235,11 @@ js::GetAnyCompartmentInZone(JS::Zone *zone)
|
|||||||
return comp.get();
|
return comp.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
JS::ObjectPtr::isAboutToBeFinalized()
|
JS::ObjectPtr::updateWeakPointerAfterGC()
|
||||||
{
|
{
|
||||||
return JS_IsAboutToBeFinalized(&value);
|
if (js::gc::IsObjectAboutToBeFinalized(value.unsafeGet()))
|
||||||
|
value = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1623,29 +1623,29 @@ GCRuntime::callFinalizeCallbacks(FreeOp *fop, JSFinalizeStatus status) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
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
|
void
|
||||||
GCRuntime::removeMovingGCCallback(JSMovingGCCallback callback)
|
GCRuntime::removeWeakPointerCallback(JSWeakPointerCallback callback)
|
||||||
{
|
{
|
||||||
for (Callback<JSMovingGCCallback> *p = movingCallbacks.begin();
|
for (Callback<JSWeakPointerCallback> *p = updateWeakPointerCallbacks.begin();
|
||||||
p < movingCallbacks.end(); p++)
|
p < updateWeakPointerCallbacks.end(); p++)
|
||||||
{
|
{
|
||||||
if (p->op == callback) {
|
if (p->op == callback) {
|
||||||
movingCallbacks.erase(p);
|
updateWeakPointerCallbacks.erase(p);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GCRuntime::callMovingGCCallbacks() const
|
GCRuntime::callWeakPointerCallbacks() const
|
||||||
{
|
{
|
||||||
for (const Callback<JSMovingGCCallback> *p = movingCallbacks.begin();
|
for (const Callback<JSWeakPointerCallback> *p = updateWeakPointerCallbacks.begin();
|
||||||
p < movingCallbacks.end(); p++)
|
p < updateWeakPointerCallbacks.end(); p++)
|
||||||
{
|
{
|
||||||
p->op(rt, p->data);
|
p->op(rt, p->data);
|
||||||
}
|
}
|
||||||
@ -2461,7 +2461,7 @@ GCRuntime::updatePointersToRelocatedCells()
|
|||||||
MovingTracer::Sweep(&trc);
|
MovingTracer::Sweep(&trc);
|
||||||
|
|
||||||
// Call callbacks to get the rest of the system to fixup other untraced pointers.
|
// Call callbacks to get the rest of the system to fixup other untraced pointers.
|
||||||
callMovingGCCallbacks();
|
callWeakPointerCallbacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -4636,6 +4636,7 @@ GCRuntime::beginSweepingZoneGroup()
|
|||||||
{
|
{
|
||||||
gcstats::AutoPhase ap(stats, gcstats::PHASE_FINALIZE_START);
|
gcstats::AutoPhase ap(stats, gcstats::PHASE_FINALIZE_START);
|
||||||
callFinalizeCallbacks(&fop, JSFINALIZE_GROUP_START);
|
callFinalizeCallbacks(&fop, JSFINALIZE_GROUP_START);
|
||||||
|
callWeakPointerCallbacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sweepingAtoms) {
|
if (sweepingAtoms) {
|
||||||
|
@ -789,17 +789,6 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp *fop,
|
|||||||
MOZ_ASSERT(!self->mGCIsRunning, "bad state");
|
MOZ_ASSERT(!self->mGCIsRunning, "bad state");
|
||||||
self->mGCIsRunning = true;
|
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;
|
self->mDoingFinalization = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -969,14 +958,14 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp *fop,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void
|
/* 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);
|
XPCJSRuntime *self = static_cast<XPCJSRuntime *>(data);
|
||||||
|
|
||||||
self->mWrappedJSMap->UpdateWeakPointersAfterGC(self);
|
self->mWrappedJSMap->UpdateWeakPointersAfterGC(self);
|
||||||
MOZ_ASSERT(self->WrappedJSToReleaseArray().IsEmpty());
|
|
||||||
|
|
||||||
XPCWrappedNativeScope::UpdateWeakPointersAfterGC(self);
|
XPCWrappedNativeScope::UpdateWeakPointersAfterGC(self);
|
||||||
}
|
}
|
||||||
@ -1547,7 +1536,7 @@ XPCJSRuntime::~XPCJSRuntime()
|
|||||||
// callback if we aren't careful. Null out the relevant callbacks.
|
// callback if we aren't careful. Null out the relevant callbacks.
|
||||||
js::SetActivityCallback(Runtime(), nullptr, nullptr);
|
js::SetActivityCallback(Runtime(), nullptr, nullptr);
|
||||||
JS_RemoveFinalizeCallback(Runtime(), FinalizeCallback);
|
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
|
// Clear any pending exception. It might be an XPCWrappedJS, and if we try
|
||||||
// to destroy it later we will crash.
|
// to destroy it later we will crash.
|
||||||
@ -3246,7 +3235,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
|
|||||||
JS_SetCompartmentNameCallback(runtime, CompartmentNameCallback);
|
JS_SetCompartmentNameCallback(runtime, CompartmentNameCallback);
|
||||||
mPrevGCSliceCallback = JS::SetGCSliceCallback(runtime, GCSliceCallback);
|
mPrevGCSliceCallback = JS::SetGCSliceCallback(runtime, GCSliceCallback);
|
||||||
JS_AddFinalizeCallback(runtime, FinalizeCallback, nullptr);
|
JS_AddFinalizeCallback(runtime, FinalizeCallback, nullptr);
|
||||||
JS_AddMovingGCCallback(runtime, MovingGCCallback, this);
|
JS_AddWeakPointerCallback(runtime, WeakPointerCallback, this);
|
||||||
JS_SetWrapObjectCallbacks(runtime, &WrapObjectCallbacks);
|
JS_SetWrapObjectCallbacks(runtime, &WrapObjectCallbacks);
|
||||||
js::SetPreserveWrapperCallback(runtime, PreserveWrapper);
|
js::SetPreserveWrapperCallback(runtime, PreserveWrapper);
|
||||||
#ifdef MOZ_CRASHREPORTER
|
#ifdef MOZ_CRASHREPORTER
|
||||||
|
@ -88,8 +88,11 @@ void
|
|||||||
JSObject2WrappedJSMap::UpdateWeakPointersAfterGC(XPCJSRuntime *runtime)
|
JSObject2WrappedJSMap::UpdateWeakPointersAfterGC(XPCJSRuntime *runtime)
|
||||||
{
|
{
|
||||||
// Check all wrappers and update their JSObject pointer if it has been
|
// 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
|
// moved, or if it is about to be finalized queue the wrapper for
|
||||||
// finalized.
|
// 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();
|
nsTArray<nsXPCWrappedJS*> &dying = runtime->WrappedJSToReleaseArray();
|
||||||
MOZ_ASSERT(dying.IsEmpty());
|
MOZ_ASSERT(dying.IsEmpty());
|
||||||
@ -102,24 +105,29 @@ JSObject2WrappedJSMap::UpdateWeakPointersAfterGC(XPCJSRuntime *runtime)
|
|||||||
while (wrapper) {
|
while (wrapper) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (!wrapper->IsSubjectToFinalization()) {
|
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 *obj = wrapper->GetJSObjectPreserveColor();
|
||||||
JSObject *prior = obj;
|
JSObject *prior = obj;
|
||||||
MOZ_ASSERT(!JS_IsAboutToBeFinalizedUnbarriered(&obj));
|
JS_UpdateWeakPointerAfterGCUnbarriered(&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);
|
MOZ_ASSERT(obj == prior);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (wrapper->IsSubjectToFinalization() && wrapper->IsObjectAboutToBeFinalized())
|
if (wrapper->IsSubjectToFinalization()) {
|
||||||
dying.AppendElement(wrapper);
|
wrapper->UpdateObjectPointerAfterGC();
|
||||||
|
if (!wrapper->GetJSObjectPreserveColor())
|
||||||
|
dying.AppendElement(wrapper);
|
||||||
|
}
|
||||||
wrapper = wrapper->GetNextWrapper();
|
wrapper = wrapper->GetNextWrapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove or update the JSObject key in the table if necessary.
|
// Remove or update the JSObject key in the table if necessary.
|
||||||
JSObject *obj = e.front().key();
|
JSObject *obj = e.front().key();
|
||||||
JSObject *prior = obj;
|
JSObject *prior = obj;
|
||||||
if (JS_IsAboutToBeFinalizedUnbarriered(&obj))
|
JS_UpdateWeakPointerAfterGCUnbarriered(&obj);
|
||||||
|
if (!obj)
|
||||||
e.removeFront();
|
e.removeFront();
|
||||||
else if (obj != prior)
|
else if (obj != prior)
|
||||||
e.rekeyFront(obj);
|
e.rekeyFront(obj);
|
||||||
|
@ -657,11 +657,14 @@ public:
|
|||||||
|
|
||||||
void Sweep() {
|
void Sweep() {
|
||||||
for (Map::Enum e(mTable); !e.empty(); e.popFront()) {
|
for (Map::Enum e(mTable); !e.empty(); e.popFront()) {
|
||||||
JSObject *updated = e.front().key();
|
JSObject *key = e.front().key();
|
||||||
if (JS_IsAboutToBeFinalizedUnbarriered(&updated) || JS_IsAboutToBeFinalized(&e.front().value()))
|
JS::Heap<JSObject *> *valuep = &e.front().value();
|
||||||
|
JS_UpdateWeakPointerAfterGCUnbarriered(&key);
|
||||||
|
JS_UpdateWeakPointerAfterGC(valuep);
|
||||||
|
if (!key || !*valuep)
|
||||||
e.removeFront();
|
e.removeFront();
|
||||||
else if (updated != e.front().key())
|
else if (key != e.front().key())
|
||||||
e.rekeyFront(updated);
|
e.rekeyFront(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -940,8 +940,11 @@ XPCWrappedNative::FlatJSObjectFinalized()
|
|||||||
for (int i = XPC_WRAPPED_NATIVE_TEAROFFS_PER_CHUNK-1; i >= 0; i--, to++) {
|
for (int i = XPC_WRAPPED_NATIVE_TEAROFFS_PER_CHUNK-1; i >= 0; i--, to++) {
|
||||||
JSObject* jso = to->GetJSObjectPreserveColor();
|
JSObject* jso = to->GetJSObjectPreserveColor();
|
||||||
if (jso) {
|
if (jso) {
|
||||||
MOZ_ASSERT(JS_IsAboutToBeFinalizedUnbarriered(&jso));
|
|
||||||
JS_SetPrivate(jso, nullptr);
|
JS_SetPrivate(jso, nullptr);
|
||||||
|
#ifdef DEBUG
|
||||||
|
JS_UpdateWeakPointerAfterGCUnbarriered(&jso);
|
||||||
|
MOZ_ASSERT(!jso);
|
||||||
|
#endif
|
||||||
to->JSObjectFinalized();
|
to->JSObjectFinalized();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,16 +508,18 @@ XPCWrappedNativeScope::UpdateWeakPointersAfterGC(XPCJSRuntime* rt)
|
|||||||
// Check for finalization of the global object. Note that global
|
// Check for finalization of the global object. Note that global
|
||||||
// objects are never moved, so we don't need to handle updating the
|
// objects are never moved, so we don't need to handle updating the
|
||||||
// object pointer here.
|
// object pointer here.
|
||||||
if (cur->mGlobalJSObject && cur->mGlobalJSObject.isAboutToBeFinalized()) {
|
if (cur->mGlobalJSObject) {
|
||||||
cur->mGlobalJSObject.finalize(rt->Runtime());
|
cur->mGlobalJSObject.updateWeakPointerAfterGC();
|
||||||
// Move this scope from the live list to the dying list.
|
if (!cur->mGlobalJSObject) {
|
||||||
if (prev)
|
// Move this scope from the live list to the dying list.
|
||||||
prev->mNext = next;
|
if (prev)
|
||||||
else
|
prev->mNext = next;
|
||||||
gScopes = next;
|
else
|
||||||
cur->mNext = gDyingScopes;
|
gScopes = next;
|
||||||
gDyingScopes = cur;
|
cur->mNext = gDyingScopes;
|
||||||
cur = nullptr;
|
gDyingScopes = cur;
|
||||||
|
cur = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cur)
|
if (cur)
|
||||||
|
@ -585,7 +585,7 @@ public:
|
|||||||
JSFinalizeStatus status,
|
JSFinalizeStatus status,
|
||||||
bool isCompartmentGC,
|
bool isCompartmentGC,
|
||||||
void *data);
|
void *data);
|
||||||
static void MovingGCCallback(JSRuntime *rt, void *data);
|
static void WeakPointerCallback(JSRuntime *rt, void *data);
|
||||||
|
|
||||||
inline void AddVariantRoot(XPCTraceableVariant* variant);
|
inline void AddVariantRoot(XPCTraceableVariant* variant);
|
||||||
inline void AddWrappedJSRoot(nsXPCWrappedJS* wrappedJS);
|
inline void AddWrappedJSRoot(nsXPCWrappedJS* wrappedJS);
|
||||||
@ -2471,7 +2471,7 @@ public:
|
|||||||
// to find non-rooting wrappers for dying JS objects. See the top of
|
// to find non-rooting wrappers for dying JS objects. See the top of
|
||||||
// XPCWrappedJS.cpp for more details.
|
// XPCWrappedJS.cpp for more details.
|
||||||
bool IsSubjectToFinalization() const {return IsValid() && mRefCnt == 1;}
|
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;}
|
bool IsAggregatedToNative() const {return mRoot->mOuter != nullptr;}
|
||||||
nsISupports* GetAggregatedNativeObject() const {return mRoot->mOuter;}
|
nsISupports* GetAggregatedNativeObject() const {return mRoot->mOuter;}
|
||||||
|
Loading…
Reference in New Issue
Block a user