Bug 1273661 part 1. Add a way to construct a callback object without calling HoldJSObjects. r=smaug

This commit is contained in:
Boris Zbarsky 2016-05-18 12:23:35 -04:00
Родитель cf35c3398f
Коммит 384428f2af
3 изменённых файлов: 55 добавлений и 5 удалений

Просмотреть файл

@ -56,6 +56,15 @@ protected:
: CallbackObject(aCallbackFunction)
{
}
// See CallbackObject for an explanation of the arguments.
CallbackFunction(JSContext* aCx, JS::Handle<JSObject*> aCallable,
nsIGlobalObject* aIncumbentGlobal,
const FastCallbackConstructor&)
: CallbackObject(aCx, aCallable, aIncumbentGlobal,
FastCallbackConstructor())
{
}
};
} // namespace dom

Просмотреть файл

@ -26,7 +26,7 @@ class CallbackInterface : public CallbackObject
public:
// See CallbackObject for an explanation of the arguments.
explicit CallbackInterface(JSContext* aCx, JS::Handle<JSObject*> aCallback,
nsIGlobalObject *aIncumbentGlobal)
nsIGlobalObject* aIncumbentGlobal)
: CallbackObject(aCx, aCallback, aIncumbentGlobal)
{
}
@ -43,6 +43,14 @@ protected:
bool GetCallableProperty(JSContext* cx, JS::Handle<jsid> aPropId,
JS::MutableHandle<JS::Value> aCallable);
// See CallbackObject for an explanation of the arguments.
CallbackInterface(JSContext* aCx, JS::Handle<JSObject*> aCallable,
nsIGlobalObject* aIncumbentGlobal,
const FastCallbackConstructor&)
: CallbackObject(aCx, aCallable, aIncumbentGlobal,
FastCallbackConstructor())
{
}
};
} // namespace dom

Просмотреть файл

@ -54,7 +54,7 @@ public:
// is invoked. aCx can be nullptr, in which case no stack is
// captured.
explicit CallbackObject(JSContext* aCx, JS::Handle<JSObject*> aCallback,
nsIGlobalObject *aIncumbentGlobal)
nsIGlobalObject* aIncumbentGlobal)
{
if (aCx && JS::RuntimeOptionsRef(aCx).asyncStack()) {
JS::RootedObject stack(aCx);
@ -72,7 +72,7 @@ public:
// for that purpose.
explicit CallbackObject(JS::Handle<JSObject*> aCallback,
JS::Handle<JSObject*> aAsyncStack,
nsIGlobalObject *aIncumbentGlobal)
nsIGlobalObject* aIncumbentGlobal)
{
Init(aCallback, aAsyncStack, aIncumbentGlobal);
}
@ -163,8 +163,8 @@ protected:
}
private:
inline void Init(JSObject* aCallback, JSObject* aCreationStack,
nsIGlobalObject* aIncumbentGlobal)
inline void InitNoHold(JSObject* aCallback, JSObject* aCreationStack,
nsIGlobalObject* aIncumbentGlobal)
{
MOZ_ASSERT(aCallback && !mCallback);
// Set script objects before we hold, on the off chance that a GC could
@ -175,6 +175,12 @@ private:
mIncumbentGlobal = aIncumbentGlobal;
mIncumbentJSGlobal = aIncumbentGlobal->GetGlobalJSObject();
}
}
inline void Init(JSObject* aCallback, JSObject* aCreationStack,
nsIGlobalObject* aIncumbentGlobal)
{
InitNoHold(aCallback, aCreationStack, aIncumbentGlobal);
mozilla::HoldJSObjects(this);
}
@ -193,6 +199,33 @@ protected:
}
}
// 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. If you use this, you MUST ensure
// that the object is traced until the HoldJSObjects happens!
CallbackObject(JSContext* aCx, JS::Handle<JSObject*> aCallback,
nsIGlobalObject* aIncumbentGlobal,
const FastCallbackConstructor&)
{
if (aCx && JS::RuntimeOptionsRef(aCx).asyncStack()) {
JS::RootedObject stack(aCx);
if (!JS::CaptureCurrentStack(aCx, &stack)) {
JS_ClearPendingException(aCx);
}
InitNoHold(aCallback, stack, aIncumbentGlobal);
} else {
InitNoHold(aCallback, nullptr, aIncumbentGlobal);
}
}
// 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
// its members, directly itself, this code won't call f(), or get its members,