Bug 1960461 - make it possible to have non-refcounted CallbackObject(Base)s, r=mccr8
Differential Revision: https://phabricator.services.mozilla.com/D245759
This commit is contained in:
@@ -87,7 +87,7 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CallbackObject)
|
|||||||
// If a new member is added here, don't forget to update IsBlackForCC.
|
// If a new member is added here, don't forget to update IsBlackForCC.
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||||
|
|
||||||
void CallbackObject::Trace(JSTracer* aTracer) {
|
void CallbackObjectBase::Trace(JSTracer* aTracer) {
|
||||||
JS::TraceEdge(aTracer, &mCallback, "CallbackObject.mCallback");
|
JS::TraceEdge(aTracer, &mCallback, "CallbackObject.mCallback");
|
||||||
JS::TraceEdge(aTracer, &mCallbackGlobal, "CallbackObject.mCallbackGlobal");
|
JS::TraceEdge(aTracer, &mCallbackGlobal, "CallbackObject.mCallbackGlobal");
|
||||||
JS::TraceEdge(aTracer, &mCreationStack, "CallbackObject.mCreationStack");
|
JS::TraceEdge(aTracer, &mCreationStack, "CallbackObject.mCreationStack");
|
||||||
@@ -119,7 +119,7 @@ void CallbackObject::FinishSlowJSInitIfMoreThanOneOwner(JSContext* aCx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject* CallbackObject::Callback(JSContext* aCx) {
|
JSObject* CallbackObjectBase::Callback(JSContext* aCx) {
|
||||||
JSObject* callback = CallbackOrNull();
|
JSObject* callback = CallbackOrNull();
|
||||||
if (!callback) {
|
if (!callback) {
|
||||||
callback = JS_NewDeadWrapper(aCx);
|
callback = JS_NewDeadWrapper(aCx);
|
||||||
@@ -129,7 +129,7 @@ JSObject* CallbackObject::Callback(JSContext* aCx) {
|
|||||||
return callback;
|
return callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallbackObject::GetDescription(nsACString& aOutString) {
|
void CallbackObjectBase::GetDescription(nsACString& aOutString) {
|
||||||
JSObject* wrappedCallback = CallbackOrNull();
|
JSObject* wrappedCallback = CallbackOrNull();
|
||||||
if (!wrappedCallback) {
|
if (!wrappedCallback) {
|
||||||
aOutString.Append("<callback from a nuked compartment>");
|
aOutString.Append("<callback from a nuked compartment>");
|
||||||
@@ -188,12 +188,12 @@ void CallbackObject::GetDescription(nsACString& aOutString) {
|
|||||||
aOutString.Append(")");
|
aOutString.Append(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
|
CallbackObjectBase::CallSetup::CallSetup(CallbackObjectBase* aCallback,
|
||||||
ErrorResult& aRv,
|
ErrorResult& aRv,
|
||||||
const char* aExecutionReason,
|
const char* aExecutionReason,
|
||||||
ExceptionHandling aExceptionHandling,
|
ExceptionHandling aExceptionHandling,
|
||||||
JS::Realm* aRealm,
|
JS::Realm* aRealm,
|
||||||
bool aIsJSImplementedWebIDL)
|
bool aIsJSImplementedWebIDL)
|
||||||
: mCx(nullptr),
|
: mCx(nullptr),
|
||||||
mRealm(aRealm),
|
mRealm(aRealm),
|
||||||
mErrorResult(aRv),
|
mErrorResult(aRv),
|
||||||
@@ -319,7 +319,7 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
|
|||||||
mCallContext.emplace(cx, nullptr);
|
mCallContext.emplace(cx, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CallbackObject::CallSetup::ShouldRethrowException(
|
bool CallbackObjectBase::CallSetup::ShouldRethrowException(
|
||||||
JS::Handle<JS::Value> aException) {
|
JS::Handle<JS::Value> aException) {
|
||||||
if (mExceptionHandling == eRethrowExceptions) {
|
if (mExceptionHandling == eRethrowExceptions) {
|
||||||
MOZ_ASSERT(!mRealm);
|
MOZ_ASSERT(!mRealm);
|
||||||
@@ -340,7 +340,7 @@ bool CallbackObject::CallSetup::ShouldRethrowException(
|
|||||||
return js::GetNonCCWObjectRealm(obj) == mRealm;
|
return js::GetNonCCWObjectRealm(obj) == mRealm;
|
||||||
}
|
}
|
||||||
|
|
||||||
CallbackObject::CallSetup::~CallSetup() {
|
CallbackObjectBase::CallSetup::~CallSetup() {
|
||||||
// To get our nesting right we have to destroy our JSAutoRealm first.
|
// To get our nesting right we have to destroy our JSAutoRealm first.
|
||||||
// In particular, we want to do this before we try reporting any exceptions,
|
// In particular, we want to do this before we try reporting any exceptions,
|
||||||
// so we end up reporting them while in the realm of our entry point,
|
// so we end up reporting them while in the realm of our entry point,
|
||||||
|
|||||||
@@ -63,48 +63,15 @@ class OwningNonNull;
|
|||||||
|
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
#define DOM_CALLBACKOBJECT_IID \
|
#define DOM_CALLBACKOBJECT_IID \
|
||||||
{ \
|
{0xbe74c190, 0x6d76, 0x4991, {0x84, 0xb9, 0x65, 0x06, 0x99, 0xe6, 0x93, 0x2b}}
|
||||||
0xbe74c190, 0x6d76, 0x4991, { \
|
|
||||||
0x84, 0xb9, 0x65, 0x06, 0x99, 0xe6, 0x93, 0x2b \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
class CallbackObject : public nsISupports, public JSHolderBase {
|
class CallbackObjectBase {
|
||||||
public:
|
public:
|
||||||
NS_DECLARE_STATIC_IID_ACCESSOR(DOM_CALLBACKOBJECT_IID)
|
CallbackObjectBase() = default;
|
||||||
|
CallbackObjectBase(JSObject* aCallback, JSObject* aCallbackGlobal,
|
||||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
JSObject* aAsyncStack, nsIGlobalObject* aIncumbentGlobal) {
|
||||||
NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(CallbackObject)
|
InitNoHold(aCallback, aCallbackGlobal, aAsyncStack, aIncumbentGlobal);
|
||||||
|
|
||||||
// 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
|
|
||||||
// the entry point computed from aCallback). If no override is required, the
|
|
||||||
// caller should pass null. |aCx| is used to capture the current
|
|
||||||
// stack, which is later used as an async parent when the callback
|
|
||||||
// is invoked. aCx can be nullptr, in which case no stack is
|
|
||||||
// captured.
|
|
||||||
explicit CallbackObject(JSContext* aCx, JS::Handle<JSObject*> aCallback,
|
|
||||||
JS::Handle<JSObject*> aCallbackGlobal,
|
|
||||||
nsIGlobalObject* aIncumbentGlobal) {
|
|
||||||
if (aCx && JS::IsAsyncStackCaptureEnabledForRealm(aCx)) {
|
|
||||||
JS::Rooted<JSObject*> stack(aCx);
|
|
||||||
if (!JS::CaptureCurrentStack(aCx, &stack)) {
|
|
||||||
JS_ClearPendingException(aCx);
|
|
||||||
}
|
|
||||||
Init(aCallback, aCallbackGlobal, stack, aIncumbentGlobal);
|
|
||||||
} else {
|
|
||||||
Init(aCallback, aCallbackGlobal, nullptr, aIncumbentGlobal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Instead of capturing the current stack to use as an async parent when the
|
|
||||||
// callback is invoked, the caller can use this overload to pass in a stack
|
|
||||||
// for that purpose.
|
|
||||||
explicit CallbackObject(JSObject* aCallback, JSObject* aCallbackGlobal,
|
|
||||||
JSObject* aAsyncStack,
|
|
||||||
nsIGlobalObject* aIncumbentGlobal) {
|
|
||||||
Init(aCallback, aCallbackGlobal, aAsyncStack, aIncumbentGlobal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is guaranteed to be non-null from the time the CallbackObject is
|
// This is guaranteed to be non-null from the time the CallbackObject is
|
||||||
@@ -177,10 +144,6 @@ class CallbackObject : public nsISupports, public JSHolderBase {
|
|||||||
// "<functionName> (<sourceURL>:<lineNumber>)"
|
// "<functionName> (<sourceURL>:<lineNumber>)"
|
||||||
void GetDescription(nsACString& aOutString);
|
void GetDescription(nsACString& aOutString);
|
||||||
|
|
||||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
|
|
||||||
return aMallocSizeOf(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used for cycle collection optimization. Should return true only if all our
|
// Used for cycle collection optimization. Should return true only if all our
|
||||||
// outgoing edges are to known-live objects. In that case, there's no point
|
// outgoing edges are to known-live objects. In that case, there's no point
|
||||||
// traversing our edges to them, because we know they can't be collected
|
// traversing our edges to them, because we know they can't be collected
|
||||||
@@ -200,36 +163,24 @@ class CallbackObject : public nsISupports, public JSHolderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~CallbackObject() { mozilla::DropJSObjectsWithKey(this); }
|
virtual ~CallbackObjectBase() = default;
|
||||||
|
|
||||||
explicit CallbackObject(CallbackObject* aCallbackObject) {
|
// Provide a way to clear this object's pointers to GC things after the
|
||||||
Init(aCallbackObject->mCallback, aCallbackObject->mCallbackGlobal,
|
// callback has been run. Note that CallbackOrNull() will return null after
|
||||||
aCallbackObject->mCreationStack, aCallbackObject->mIncumbentGlobal);
|
// this point. This should only be called if the object is known not to be
|
||||||
|
// used again, and no handles (e.g. those returned by CallbackPreserveColor)
|
||||||
|
// are in use.
|
||||||
|
void Reset() { ClearJSReferences(); }
|
||||||
|
|
||||||
|
friend class mozilla::PromiseJobRunnable;
|
||||||
|
|
||||||
|
inline void ClearJSReferences() {
|
||||||
|
mCallback = nullptr;
|
||||||
|
mCallbackGlobal = nullptr;
|
||||||
|
mCreationStack = nullptr;
|
||||||
|
mIncumbentJSGlobal = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const CallbackObject& aOther) const {
|
|
||||||
JSObject* wrappedThis = CallbackPreserveColor();
|
|
||||||
JSObject* wrappedOther = aOther.CallbackPreserveColor();
|
|
||||||
if (!wrappedThis || !wrappedOther) {
|
|
||||||
return this == &aOther;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject* thisObj = js::UncheckedUnwrap(wrappedThis);
|
|
||||||
JSObject* otherObj = js::UncheckedUnwrap(wrappedOther);
|
|
||||||
return thisObj == otherObj;
|
|
||||||
}
|
|
||||||
|
|
||||||
class JSObjectsDropper final {
|
|
||||||
public:
|
|
||||||
explicit JSObjectsDropper(CallbackObject* aHolder) : mHolder(aHolder) {}
|
|
||||||
|
|
||||||
~JSObjectsDropper() { mHolder->ClearJSObjects(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
RefPtr<CallbackObject> mHolder;
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
inline void InitNoHold(JSObject* aCallback, JSObject* aCallbackGlobal,
|
inline void InitNoHold(JSObject* aCallback, JSObject* aCallbackGlobal,
|
||||||
JSObject* aCreationStack,
|
JSObject* aCreationStack,
|
||||||
nsIGlobalObject* aIncumbentGlobal) {
|
nsIGlobalObject* aIncumbentGlobal) {
|
||||||
@@ -250,37 +201,6 @@ class CallbackObject : public nsISupports, public JSHolderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Init(JSObject* aCallback, JSObject* aCallbackGlobal,
|
|
||||||
JSObject* aCreationStack,
|
|
||||||
nsIGlobalObject* aIncumbentGlobal) {
|
|
||||||
// Set script objects before we hold, on the off chance that a GC could
|
|
||||||
// somehow happen in there... (which would be pretty odd, granted).
|
|
||||||
InitNoHold(aCallback, aCallbackGlobal, aCreationStack, aIncumbentGlobal);
|
|
||||||
mozilla::HoldJSObjectsWithKey(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Provide a way to clear this object's pointers to GC things after the
|
|
||||||
// callback has been run. Note that CallbackOrNull() will return null after
|
|
||||||
// this point. This should only be called if the object is known not to be
|
|
||||||
// used again, and no handles (e.g. those returned by CallbackPreserveColor)
|
|
||||||
// are in use.
|
|
||||||
void Reset() {
|
|
||||||
ClearJSReferences();
|
|
||||||
mozilla::DropJSObjectsWithKey(this);
|
|
||||||
}
|
|
||||||
friend class mozilla::PromiseJobRunnable;
|
|
||||||
|
|
||||||
inline void ClearJSReferences() {
|
|
||||||
mCallback = nullptr;
|
|
||||||
mCallbackGlobal = nullptr;
|
|
||||||
mCreationStack = nullptr;
|
|
||||||
mIncumbentJSGlobal = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
CallbackObject(const CallbackObject&) = delete;
|
|
||||||
CallbackObject& operator=(const CallbackObject&) = delete;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void ClearJSObjects() {
|
void ClearJSObjects() {
|
||||||
MOZ_ASSERT_IF(mIncumbentJSGlobal, mCallback);
|
MOZ_ASSERT_IF(mIncumbentJSGlobal, mCallback);
|
||||||
if (mCallback) {
|
if (mCallback) {
|
||||||
@@ -291,30 +211,6 @@ class CallbackObject : public nsISupports, public JSHolderBase {
|
|||||||
// For use from subclasses that want to be usable with Rooted.
|
// For use from subclasses that want to be usable with Rooted.
|
||||||
void Trace(JSTracer* aTracer);
|
void Trace(JSTracer* aTracer);
|
||||||
|
|
||||||
// For use from subclasses that want to be traced for a bit then possibly
|
|
||||||
// switch to HoldJSObjects and do other slow JS-related init work we might do.
|
|
||||||
// If we have more than one owner, this will HoldJSObjects and do said slow
|
|
||||||
// init work; otherwise it will just forget all our JS references.
|
|
||||||
void FinishSlowJSInitIfMoreThanOneOwner(JSContext* aCx);
|
|
||||||
|
|
||||||
// Struct used as a way to force a CallbackObject constructor to not call
|
|
||||||
// HoldJSObjects. We're putting it here so that CallbackObject subclasses will
|
|
||||||
// have access to it, but outside code will not.
|
|
||||||
//
|
|
||||||
// Places that use this need to ensure that the callback is traced (e.g. via a
|
|
||||||
// Rooted) until the HoldJSObjects call happens.
|
|
||||||
struct FastCallbackConstructor {};
|
|
||||||
|
|
||||||
// Just like the public version without the FastCallbackConstructor argument,
|
|
||||||
// except for not calling HoldJSObjects and not capturing async stacks (on the
|
|
||||||
// assumption that we will do that last whenever we decide to actually
|
|
||||||
// HoldJSObjects; see FinishSlowJSInitIfMoreThanOneOwner). If you use this,
|
|
||||||
// you MUST ensure that the object is traced until the HoldJSObjects happens!
|
|
||||||
CallbackObject(JSObject* aCallback, JSObject* aCallbackGlobal,
|
|
||||||
const FastCallbackConstructor&) {
|
|
||||||
InitNoHold(aCallback, aCallbackGlobal, nullptr, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// mCallback is not unwrapped, so it can be a cross-compartment-wrapper.
|
// mCallback is not unwrapped, so it can be a cross-compartment-wrapper.
|
||||||
// This is done to ensure that, if JS code can't call a callback f(), or get
|
// This is done to ensure that, if JS code can't call a callback f(), or get
|
||||||
// its members, directly itself, this code won't call f(), or get its members,
|
// its members, directly itself, this code won't call f(), or get its members,
|
||||||
@@ -352,7 +248,7 @@ class CallbackObject : public nsISupports, public JSHolderBase {
|
|||||||
// to the realm in which exceptions will be rethrown. In that case
|
// to the realm in which exceptions will be rethrown. In that case
|
||||||
// they will only be rethrown if that realm's principal subsumes the
|
// they will only be rethrown if that realm's principal subsumes the
|
||||||
// principal of our (unwrapped) callback.
|
// principal of our (unwrapped) callback.
|
||||||
CallSetup(CallbackObject* aCallback, ErrorResult& aRv,
|
CallSetup(CallbackObjectBase* aCallback, ErrorResult& aRv,
|
||||||
const char* aExecutionReason,
|
const char* aExecutionReason,
|
||||||
ExceptionHandling aExceptionHandling, JS::Realm* aRealm = nullptr,
|
ExceptionHandling aExceptionHandling, JS::Realm* aRealm = nullptr,
|
||||||
bool aIsJSImplementedWebIDL = false);
|
bool aIsJSImplementedWebIDL = false);
|
||||||
@@ -407,6 +303,122 @@ class CallbackObject : public nsISupports, public JSHolderBase {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CallbackObject : public nsISupports,
|
||||||
|
public CallbackObjectBase,
|
||||||
|
public JSHolderBase {
|
||||||
|
public:
|
||||||
|
NS_DECLARE_STATIC_IID_ACCESSOR(DOM_CALLBACKOBJECT_IID)
|
||||||
|
|
||||||
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
|
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
|
||||||
|
// the entry point computed from aCallback). If no override is required, the
|
||||||
|
// caller should pass null. |aCx| is used to capture the current
|
||||||
|
// stack, which is later used as an async parent when the callback
|
||||||
|
// is invoked. aCx can be nullptr, in which case no stack is
|
||||||
|
// captured.
|
||||||
|
explicit CallbackObject(JSContext* aCx, JS::Handle<JSObject*> aCallback,
|
||||||
|
JS::Handle<JSObject*> aCallbackGlobal,
|
||||||
|
nsIGlobalObject* aIncumbentGlobal) {
|
||||||
|
if (aCx && JS::IsAsyncStackCaptureEnabledForRealm(aCx)) {
|
||||||
|
JS::Rooted<JSObject*> stack(aCx);
|
||||||
|
if (!JS::CaptureCurrentStack(aCx, &stack)) {
|
||||||
|
JS_ClearPendingException(aCx);
|
||||||
|
}
|
||||||
|
Init(aCallback, aCallbackGlobal, stack, aIncumbentGlobal);
|
||||||
|
} else {
|
||||||
|
Init(aCallback, aCallbackGlobal, nullptr, aIncumbentGlobal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instead of capturing the current stack to use as an async parent when the
|
||||||
|
// callback is invoked, the caller can use this overload to pass in a stack
|
||||||
|
// for that purpose.
|
||||||
|
explicit CallbackObject(JSObject* aCallback, JSObject* aCallbackGlobal,
|
||||||
|
JSObject* aAsyncStack,
|
||||||
|
nsIGlobalObject* aIncumbentGlobal) {
|
||||||
|
Init(aCallback, aCallbackGlobal, aAsyncStack, aIncumbentGlobal);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
|
||||||
|
return aMallocSizeOf(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset() {
|
||||||
|
CallbackObjectBase::Reset();
|
||||||
|
mozilla::DropJSObjectsWithKey(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual ~CallbackObject() { mozilla::DropJSObjectsWithKey(this); }
|
||||||
|
|
||||||
|
explicit CallbackObject(CallbackObject* aCallbackObject) {
|
||||||
|
Init(aCallbackObject->mCallback, aCallbackObject->mCallbackGlobal,
|
||||||
|
aCallbackObject->mCreationStack, aCallbackObject->mIncumbentGlobal);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For use from subclasses that want to be traced for a bit then possibly
|
||||||
|
// switch to HoldJSObjects and do other slow JS-related init work we might do.
|
||||||
|
// If we have more than one owner, this will HoldJSObjects and do said slow
|
||||||
|
// init work; otherwise it will just forget all our JS references.
|
||||||
|
void FinishSlowJSInitIfMoreThanOneOwner(JSContext* aCx);
|
||||||
|
|
||||||
|
// Struct used as a way to force a CallbackObject constructor to not call
|
||||||
|
// HoldJSObjects. We're putting it here so that CallbackObject subclasses will
|
||||||
|
// have access to it, but outside code will not.
|
||||||
|
//
|
||||||
|
// Places that use this need to ensure that the callback is traced (e.g. via a
|
||||||
|
// Rooted) until the HoldJSObjects call happens.
|
||||||
|
struct FastCallbackConstructor {};
|
||||||
|
|
||||||
|
// Just like the public version without the FastCallbackConstructor argument,
|
||||||
|
// except for not calling HoldJSObjects and not capturing async stacks (on the
|
||||||
|
// assumption that we will do that last whenever we decide to actually
|
||||||
|
// HoldJSObjects; see FinishSlowJSInitIfMoreThanOneOwner). If you use this,
|
||||||
|
// you MUST ensure that the object is traced until the HoldJSObjects happens!
|
||||||
|
CallbackObject(JSObject* aCallback, JSObject* aCallbackGlobal,
|
||||||
|
const FastCallbackConstructor&) {
|
||||||
|
InitNoHold(aCallback, aCallbackGlobal, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const CallbackObject& aOther) const {
|
||||||
|
JSObject* wrappedThis = CallbackPreserveColor();
|
||||||
|
JSObject* wrappedOther = aOther.CallbackPreserveColor();
|
||||||
|
if (!wrappedThis || !wrappedOther) {
|
||||||
|
return this == &aOther;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSObject* thisObj = js::UncheckedUnwrap(wrappedThis);
|
||||||
|
JSObject* otherObj = js::UncheckedUnwrap(wrappedOther);
|
||||||
|
return thisObj == otherObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
class JSObjectsDropper final {
|
||||||
|
public:
|
||||||
|
explicit JSObjectsDropper(CallbackObject* aHolder) : mHolder(aHolder) {}
|
||||||
|
|
||||||
|
~JSObjectsDropper() { mHolder->ClearJSObjects(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
RefPtr<CallbackObject> mHolder;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
CallbackObject(const CallbackObject&) = delete;
|
||||||
|
CallbackObject& operator=(const CallbackObject&) = delete;
|
||||||
|
|
||||||
|
inline void Init(JSObject* aCallback, JSObject* aCallbackGlobal,
|
||||||
|
JSObject* aCreationStack,
|
||||||
|
nsIGlobalObject* aIncumbentGlobal) {
|
||||||
|
// Set script objects before we hold, on the off chance that a GC could
|
||||||
|
// somehow happen in there... (which would be pretty odd, granted).
|
||||||
|
InitNoHold(aCallback, aCallbackGlobal, aCreationStack, aIncumbentGlobal);
|
||||||
|
mozilla::HoldJSObjectsWithKey(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <class WebIDLCallbackT, class XPCOMCallbackT>
|
template <class WebIDLCallbackT, class XPCOMCallbackT>
|
||||||
class CallbackObjectHolder;
|
class CallbackObjectHolder;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user