зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1273251: Part 4 - Drop CallbackObject's JS objects for nuked compartments during CC. r=peterv,mccr8
MozReview-Commit-ID: 6lPdmUtKREt --HG-- extra : rebase_source : c6a53f914b5bbe829de6f5a080cfb9ee93146bd3
This commit is contained in:
Родитель
729b7a2019
Коммит
67fcf5b318
|
@ -36,6 +36,44 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CallbackObject)
|
|||
tmp->DropJSObjects();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIncumbentGlobal)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(CallbackObject)
|
||||
JSObject* callback = tmp->CallbackPreserveColor();
|
||||
|
||||
if (!aRemovingAllowed) {
|
||||
// If our callback has been cleared, we can't be part of a garbage cycle.
|
||||
return !callback;
|
||||
}
|
||||
|
||||
// mCallback is always wrapped for the CallbackObject's incumbent global. In
|
||||
// the case where the real callback is in a different compartment, we have a
|
||||
// cross-compartment wrapper, and it will automatically be cut when its
|
||||
// compartment is nuked. In the case where it is in the same compartment, we
|
||||
// have a reference to the real function. Since that means there are no
|
||||
// wrappers to cut, we need to check whether the compartment is still alive,
|
||||
// and drop the references if it is not.
|
||||
|
||||
if (MOZ_UNLIKELY(!callback)) {
|
||||
return true;
|
||||
}
|
||||
auto pvt = xpc::CompartmentPrivate::Get(callback);
|
||||
if (MOZ_LIKELY(tmp->mIncumbentGlobal && pvt) && MOZ_UNLIKELY(pvt->wasNuked)) {
|
||||
// It's not safe to release our global reference or drop our JS objects at
|
||||
// this point, so defer their finalization until CC is finished.
|
||||
AddForDeferredFinalization(new JSObjectsDropper(tmp));
|
||||
DeferredFinalize(tmp->mIncumbentGlobal.forget().take());
|
||||
return true;
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(CallbackObject)
|
||||
return !tmp->mCallback;
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(CallbackObject)
|
||||
return !tmp->mCallback;
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CallbackObject)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIncumbentGlobal)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
|
|
@ -46,7 +46,7 @@ public:
|
|||
NS_DECLARE_STATIC_IID_ACCESSOR(DOM_CALLBACKOBJECT_IID)
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CallbackObject)
|
||||
NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(CallbackObject)
|
||||
|
||||
// The caller may pass a global object which will act as an override for the
|
||||
// incumbent script settings object when the callback is invoked (overriding
|
||||
|
@ -179,6 +179,22 @@ protected:
|
|||
return thisObj == otherObj;
|
||||
}
|
||||
|
||||
class JSObjectsDropper final
|
||||
{
|
||||
public:
|
||||
explicit JSObjectsDropper(CallbackObject* aHolder)
|
||||
: mHolder(aHolder)
|
||||
{}
|
||||
|
||||
~JSObjectsDropper()
|
||||
{
|
||||
mHolder->DropJSObjects();
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<CallbackObject> mHolder;
|
||||
};
|
||||
|
||||
private:
|
||||
inline void InitNoHold(JSObject* aCallback, JSObject* aCreationStack,
|
||||
nsIGlobalObject* aIncumbentGlobal)
|
||||
|
@ -536,7 +552,9 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
|
|||
const char* aName,
|
||||
uint32_t aFlags = 0)
|
||||
{
|
||||
CycleCollectionNoteChild(aCallback, aField.GetISupports(), aName, aFlags);
|
||||
if (aField) {
|
||||
CycleCollectionNoteChild(aCallback, aField.GetISupports(), aName, aFlags);
|
||||
}
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
|
|
Загрузка…
Ссылка в новой задаче