Bug 995163 - wrap the Promise value in NativePromiseCallback, r=bz

This commit is contained in:
Andrea Marchesini 2014-04-29 22:12:14 +01:00
parent a847cfea9d
commit fc5fc8f292
3 changed files with 65 additions and 51 deletions

View File

@ -865,11 +865,20 @@ Promise::RunTask()
mResolveCallbacks.Clear();
mRejectCallbacks.Clear();
ThreadsafeAutoJSContext cx; // Just for rooting.
ThreadsafeAutoJSContext cx;
JS::Rooted<JS::Value> value(cx, mResult);
JS::Rooted<JSObject*> wrapper(cx, GetOrCreateWrapper(cx));
if (!wrapper) {
return;
}
JSAutoCompartment ac(cx, wrapper);
if (!MaybeWrapValue(cx, &value)) {
return;
}
for (uint32_t i = 0; i < callbacks.Length(); ++i) {
callbacks[i]->Call(value);
callbacks[i]->Call(cx, value);
}
}

View File

@ -82,19 +82,19 @@ ResolvePromiseCallback::~ResolvePromiseCallback()
}
void
ResolvePromiseCallback::Call(JS::Handle<JS::Value> aValue)
ResolvePromiseCallback::Call(JSContext* aCx,
JS::Handle<JS::Value> aValue)
{
// Run resolver's algorithm with value and the synchronous flag set.
ThreadsafeAutoSafeJSContext cx;
JSAutoCompartment ac(cx, mGlobal);
JS::Rooted<JS::Value> value(cx, aValue);
if (!JS_WrapValue(cx, &value)) {
JSAutoCompartment ac(aCx, mGlobal);
JS::Rooted<JS::Value> value(aCx, aValue);
if (!JS_WrapValue(aCx, &value)) {
NS_WARNING("Failed to wrap value into the right compartment.");
return;
}
mPromise->ResolveInternal(cx, value, Promise::SyncTask);
mPromise->ResolveInternal(aCx, value, Promise::SyncTask);
}
// RejectPromiseCallback
@ -142,20 +142,20 @@ RejectPromiseCallback::~RejectPromiseCallback()
}
void
RejectPromiseCallback::Call(JS::Handle<JS::Value> aValue)
RejectPromiseCallback::Call(JSContext* aCx,
JS::Handle<JS::Value> aValue)
{
// Run resolver's algorithm with value and the synchronous flag set.
ThreadsafeAutoSafeJSContext cx;
JSAutoCompartment ac(cx, mGlobal);
JS::Rooted<JS::Value> value(cx, aValue);
if (!JS_WrapValue(cx, &value)) {
JSAutoCompartment ac(aCx, mGlobal);
JS::Rooted<JS::Value> value(aCx, aValue);
if (!JS_WrapValue(aCx, &value)) {
NS_WARNING("Failed to wrap value into the right compartment.");
return;
}
mPromise->RejectInternal(cx, value, Promise::SyncTask);
mPromise->RejectInternal(aCx, value, Promise::SyncTask);
}
// WrapperPromiseCallback
@ -205,13 +205,12 @@ WrapperPromiseCallback::~WrapperPromiseCallback()
}
void
WrapperPromiseCallback::Call(JS::Handle<JS::Value> aValue)
WrapperPromiseCallback::Call(JSContext* aCx,
JS::Handle<JS::Value> aValue)
{
ThreadsafeAutoSafeJSContext cx;
JSAutoCompartment ac(cx, mGlobal);
JS::Rooted<JS::Value> value(cx, aValue);
if (!JS_WrapValue(cx, &value)) {
JSAutoCompartment ac(aCx, mGlobal);
JS::Rooted<JS::Value> value(aCx, aValue);
if (!JS_WrapValue(aCx, &value)) {
NS_WARNING("Failed to wrap value into the right compartment.");
return;
}
@ -220,27 +219,27 @@ WrapperPromiseCallback::Call(JS::Handle<JS::Value> aValue)
// If invoking callback threw an exception, run resolver's reject with the
// thrown exception as argument and the synchronous flag set.
JS::Rooted<JS::Value> retValue(cx,
JS::Rooted<JS::Value> retValue(aCx,
mCallback->Call(value, rv, CallbackObject::eRethrowExceptions));
rv.WouldReportJSException();
if (rv.Failed() && rv.IsJSException()) {
JS::Rooted<JS::Value> value(cx);
rv.StealJSException(cx, &value);
JS::Rooted<JS::Value> value(aCx);
rv.StealJSException(aCx, &value);
if (!JS_WrapValue(cx, &value)) {
if (!JS_WrapValue(aCx, &value)) {
NS_WARNING("Failed to wrap value into the right compartment.");
return;
}
mNextPromise->RejectInternal(cx, value, Promise::SyncTask);
mNextPromise->RejectInternal(aCx, value, Promise::SyncTask);
return;
}
// If the return value is the same as the promise itself, throw TypeError.
if (retValue.isObject()) {
JS::Rooted<JSObject*> valueObj(cx, &retValue.toObject());
JS::Rooted<JSObject*> valueObj(aCx, &retValue.toObject());
Promise* returnedPromise;
nsresult r = UNWRAP_OBJECT(Promise, valueObj, returnedPromise);
@ -250,63 +249,63 @@ WrapperPromiseCallback::Call(JS::Handle<JS::Value> aValue)
// Try to get some information about the callback to report a sane error,
// but don't try too hard (only deals with scripted functions).
JS::Rooted<JSObject*> unwrapped(cx,
JS::Rooted<JSObject*> unwrapped(aCx,
js::CheckedUnwrap(mCallback->Callback()));
if (unwrapped) {
JSAutoCompartment ac(cx, unwrapped);
if (JS_ObjectIsFunction(cx, unwrapped)) {
JS::Rooted<JS::Value> asValue(cx, JS::ObjectValue(*unwrapped));
JS::Rooted<JSFunction*> func(cx, JS_ValueToFunction(cx, asValue));
JSAutoCompartment ac(aCx, unwrapped);
if (JS_ObjectIsFunction(aCx, unwrapped)) {
JS::Rooted<JS::Value> asValue(aCx, JS::ObjectValue(*unwrapped));
JS::Rooted<JSFunction*> func(aCx, JS_ValueToFunction(aCx, asValue));
MOZ_ASSERT(func);
JSScript* script = JS_GetFunctionScript(cx, func);
JSScript* script = JS_GetFunctionScript(aCx, func);
if (script) {
fileName = JS_GetScriptFilename(script);
lineNumber = JS_GetScriptBaseLineNumber(cx, script);
lineNumber = JS_GetScriptBaseLineNumber(aCx, script);
}
}
}
// We're back in aValue's compartment here.
JS::Rooted<JSString*> stack(cx, JS_GetEmptyString(JS_GetRuntime(cx)));
JS::Rooted<JSString*> fn(cx, JS_NewStringCopyZ(cx, fileName));
JS::Rooted<JSString*> stack(aCx, JS_GetEmptyString(JS_GetRuntime(aCx)));
JS::Rooted<JSString*> fn(aCx, JS_NewStringCopyZ(aCx, fileName));
if (!fn) {
// Out of memory. Promise will stay unresolved.
JS_ClearPendingException(cx);
JS_ClearPendingException(aCx);
return;
}
JS::Rooted<JSString*> message(cx,
JS_NewStringCopyZ(cx,
JS::Rooted<JSString*> message(aCx,
JS_NewStringCopyZ(aCx,
"then() cannot return same Promise that it resolves."));
if (!message) {
// Out of memory. Promise will stay unresolved.
JS_ClearPendingException(cx);
JS_ClearPendingException(aCx);
return;
}
JS::Rooted<JS::Value> typeError(cx);
if (!JS::CreateTypeError(cx, stack, fn, lineNumber, 0,
JS::Rooted<JS::Value> typeError(aCx);
if (!JS::CreateTypeError(aCx, stack, fn, lineNumber, 0,
nullptr, message, &typeError)) {
// Out of memory. Promise will stay unresolved.
JS_ClearPendingException(cx);
JS_ClearPendingException(aCx);
return;
}
mNextPromise->RejectInternal(cx, typeError, Promise::SyncTask);
mNextPromise->RejectInternal(aCx, typeError, Promise::SyncTask);
return;
}
}
// Otherwise, run resolver's resolve with value and the synchronous flag
// set.
if (!JS_WrapValue(cx, &retValue)) {
if (!JS_WrapValue(aCx, &retValue)) {
NS_WARNING("Failed to wrap value into the right compartment.");
return;
}
mNextPromise->ResolveInternal(cx, retValue, Promise::SyncTask);
mNextPromise->ResolveInternal(aCx, retValue, Promise::SyncTask);
}
// NativePromiseCallback
@ -335,7 +334,8 @@ NativePromiseCallback::~NativePromiseCallback()
}
void
NativePromiseCallback::Call(JS::Handle<JS::Value> aValue)
NativePromiseCallback::Call(JSContext* aCx,
JS::Handle<JS::Value> aValue)
{
if (mState == Promise::Resolved) {
mHandler->ResolvedCallback(aValue);

View File

@ -24,7 +24,8 @@ public:
PromiseCallback();
virtual ~PromiseCallback();
virtual void Call(JS::Handle<JS::Value> aValue) = 0;
virtual void Call(JSContext* aCx,
JS::Handle<JS::Value> aValue) = 0;
enum Task {
Resolve,
@ -47,7 +48,8 @@ public:
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WrapperPromiseCallback,
PromiseCallback)
void Call(JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
void Call(JSContext* aCx,
JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
WrapperPromiseCallback(Promise* aNextPromise, JS::Handle<JSObject*> aGlobal,
AnyCallback* aCallback);
@ -68,7 +70,8 @@ public:
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ResolvePromiseCallback,
PromiseCallback)
void Call(JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
void Call(JSContext* aCx,
JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
ResolvePromiseCallback(Promise* aPromise, JS::Handle<JSObject*> aGlobal);
~ResolvePromiseCallback();
@ -87,7 +90,8 @@ public:
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(RejectPromiseCallback,
PromiseCallback)
void Call(JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
void Call(JSContext* aCx,
JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
RejectPromiseCallback(Promise* aPromise, JS::Handle<JSObject*> aGlobal);
~RejectPromiseCallback();
@ -105,7 +109,8 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(NativePromiseCallback,
PromiseCallback)
void Call(JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
void Call(JSContext* aCx,
JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
NativePromiseCallback(PromiseNativeHandler* aHandler,
Promise::PromiseState aState);