author | Boris Zbarsky <bzbarsky@mit.edu> |
Sat, 10 Feb 2018 01:34:10 -0500 | |
changeset 403230 | fa2042520eb9252f535ba369b7dcb678c1c96703 |
parent 403229 | 1f3a5b496acd2288cc8cf0c32af86cb35157ea4e |
child 403231 | 4ad4e15fed408dd842664fd7117d27290d294133 |
push id | 99753 |
push user | bzbarsky@mozilla.com |
push date | Sat, 10 Feb 2018 06:36:44 +0000 |
treeherder | mozilla-inbound@fa2042520eb9 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bholley |
bugs | 1436276 |
milestone | 60.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -2908,62 +2908,57 @@ GenericBindingGetter(JSContext* cx, unsi } #endif return ok; } bool GenericPromiseReturningBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp) { - // Make sure to save the callee before someone maybe messes with rval(). JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - JS::Rooted<JSObject*> callee(cx, &args.callee()); // We could invoke GenericBindingGetter here, but that involves an // extra call. Manually inline it instead. const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev()); prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID); if (!args.thisv().isObject()) { ThrowInvalidThis(cx, args, false, protoID); - return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee), - args.rval()); + return ConvertExceptionToPromise(cx, args.rval()); } JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject()); // NOTE: we want to leave obj in its initial compartment, so don't want to // pass it to UnwrapObject. JS::Rooted<JSObject*> rootSelf(cx, obj); void* self; { binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf); nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(wrapper, self, protoID, info->depth); if (NS_FAILED(rv)) { ThrowInvalidThis(cx, args, rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO, protoID); - return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee), - args.rval()); + return ConvertExceptionToPromise(cx, args.rval()); } } MOZ_ASSERT(info->type() == JSJitInfo::Getter); JSJitGetterOp getter = info->getter; bool ok = getter(cx, obj, self, JSJitGetterCallArgs(args)); if (ok) { #ifdef DEBUG AssertReturnTypeMatchesJitinfo(info, args.rval()); #endif return true; } // Promise-returning getters always return objects MOZ_ASSERT(info->returnType() == JSVAL_TYPE_OBJECT); - return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee), - args.rval()); + return ConvertExceptionToPromise(cx, args.rval()); } bool GenericBindingSetter(JSContext* cx, unsigned argc, JS::Value* vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev()); prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID); @@ -3039,114 +3034,99 @@ GenericBindingMethod(JSContext* cx, unsi } #endif return ok; } bool GenericPromiseReturningBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp) { - // Make sure to save the callee before someone maybe messes with rval(). JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - JS::Rooted<JSObject*> callee(cx, &args.callee()); // We could invoke GenericBindingMethod here, but that involves an // extra call. Manually inline it instead. const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev()); prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID); if (!args.thisv().isObject()) { ThrowInvalidThis(cx, args, false, protoID); - return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee), - args.rval()); + return ConvertExceptionToPromise(cx, args.rval()); } JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject()); // NOTE: we want to leave obj in its initial compartment, so don't want to // pass it to UnwrapObject. JS::Rooted<JSObject*> rootSelf(cx, obj); void* self; { binding_detail::MutableObjectHandleWrapper wrapper(&rootSelf); nsresult rv = binding_detail::UnwrapObjectInternal<void, true>(wrapper, self, protoID, info->depth); if (NS_FAILED(rv)) { ThrowInvalidThis(cx, args, rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO, protoID); - return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee), - args.rval()); + return ConvertExceptionToPromise(cx, args.rval()); } } MOZ_ASSERT(info->type() == JSJitInfo::Method); JSJitMethodOp method = info->method; bool ok = method(cx, obj, self, JSJitMethodCallArgs(args)); if (ok) { #ifdef DEBUG AssertReturnTypeMatchesJitinfo(info, args.rval()); #endif return true; } // Promise-returning methods always return objects MOZ_ASSERT(info->returnType() == JSVAL_TYPE_OBJECT); - return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee), - args.rval()); + return ConvertExceptionToPromise(cx, args.rval()); } bool StaticMethodPromiseWrapper(JSContext* cx, unsigned argc, JS::Value* vp) { - // Make sure to save the callee before someone maybe messes with rval(). JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - JS::Rooted<JSObject*> callee(cx, &args.callee()); const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev()); MOZ_ASSERT(info); MOZ_ASSERT(info->type() == JSJitInfo::StaticMethod); bool ok = info->staticMethod(cx, argc, vp); if (ok) { return true; } - return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee), - args.rval()); + return ConvertExceptionToPromise(cx, args.rval()); } bool ConvertExceptionToPromise(JSContext* cx, - JSObject* promiseScope, JS::MutableHandle<JS::Value> rval) { - { - JSAutoCompartment ac(cx, promiseScope); - - JS::Rooted<JS::Value> exn(cx); - if (!JS_GetPendingException(cx, &exn)) { - // This is very important: if there is no pending exception here but we're - // ending up in this code, that means the callee threw an uncatchable - // exception. Just propagate that out as-is. - return false; - } - - JS_ClearPendingException(cx); - - JSObject* promise = JS::CallOriginalPromiseReject(cx, exn); - if (!promise) { - // We just give up. Put the exception back. - JS_SetPendingException(cx, exn); - return false; - } - - rval.setObject(*promise); + JS::Rooted<JS::Value> exn(cx); + if (!JS_GetPendingException(cx, &exn)) { + // This is very important: if there is no pending exception here but we're + // ending up in this code, that means the callee threw an uncatchable + // exception. Just propagate that out as-is. + return false; } - // Now make sure we rewrap promise back into the compartment we want - return JS_WrapValue(cx, rval); + JS_ClearPendingException(cx); + + JSObject* promise = JS::CallOriginalPromiseReject(cx, exn); + if (!promise) { + // We just give up. Put the exception back. + JS_SetPendingException(cx, exn); + return false; + } + + rval.setObject(*promise); + return true; } /* static */ void CreateGlobalOptions<nsGlobalWindowInner>::TraceGlobal(JSTracer* aTrc, JSObject* aObj) { xpc::TraceXPCGlobal(aTrc, aObj); }
--- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -3242,21 +3242,18 @@ bool StaticMethodPromiseWrapper(JSContext* cx, unsigned argc, JS::Value* vp); // ConvertExceptionToPromise should only be called when we have an error // condition (e.g. returned false from a JSAPI method). Note that there may be // no exception on cx, in which case this is an uncatchable failure that will // simply be propagated. Otherwise this method will attempt to convert the // exception to a Promise rejected with the exception that it will store in // rval. -// -// promiseScope should be the scope in which the Promise should be created. bool ConvertExceptionToPromise(JSContext* cx, - JSObject* promiseScope, JS::MutableHandle<JS::Value> rval); #ifdef DEBUG void AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitinfo, JS::Handle<JS::Value> aValue); #endif
--- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -8838,48 +8838,40 @@ class CGGenericPromiseReturningMethod(CG """ A class for generating the C++ code for an IDL method that returns a Promise. Does not handle cross-origin this. """ def __init__(self, descriptor): unwrapFailureCode = dedent(""" ThrowInvalidThis(cx, args, %%(securityError)s, "%s");\n - return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee), - args.rval());\n""" % + return ConvertExceptionToPromise(cx, args.rval());\n""" % descriptor.interface.identifier.name) name = "genericPromiseReturningMethod" - customCallArgs = dedent(""" - JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - // Make sure to save the callee before someone maybe messes with rval(). - JS::Rooted<JSObject*> callee(cx, &args.callee()); - """) CGAbstractBindingMethod.__init__(self, descriptor, name, JSNativeArguments(), - callArgs=customCallArgs, unwrapFailureCode=unwrapFailureCode) def generate_code(self): return CGGeneric(dedent(""" const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev()); MOZ_ASSERT(info->type() == JSJitInfo::Method); JSJitMethodOp method = info->method; bool ok = method(cx, obj, self, JSJitMethodCallArgs(args)); if (ok) { #ifdef DEBUG AssertReturnTypeMatchesJitinfo(info, args.rval()); #endif return true; } MOZ_ASSERT(info->returnType() == JSVAL_TYPE_OBJECT); - return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee), - args.rval()); + return ConvertExceptionToPromise(cx, args.rval()); """)) class CGSpecializedMethod(CGAbstractStaticMethod): """ A class for generating the C++ code for a specialized method that the JIT can call with lower overhead. """ @@ -8915,25 +8907,21 @@ class CGMethodPromiseWrapper(CGAbstractS name = self.makeName(methodToWrap.name) args = list(methodToWrap.args) CGAbstractStaticMethod.__init__(self, descriptor, name, 'bool', args, canRunScript=True) def definition_body(self): return fill( """ - // Make sure to save the callee before someone maybe messes - // with rval(). - JS::Rooted<JSObject*> callee(cx, &args.callee()); bool ok = ${methodName}(${args}); if (ok) { return true; } - return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee), - args.rval()); + return ConvertExceptionToPromise(cx, args.rval()); """, methodName=self.method.name, args=", ".join(arg.name for arg in self.args)) @staticmethod def makeName(methodName): return methodName + "_promiseWrapper" @@ -9206,31 +9194,23 @@ class CGGenericPromiseReturningGetter(CG A class for generating the C++ code for an IDL getter that returns a Promise. Does not handle cross-origin this or [LenientThis]. """ def __init__(self, descriptor): unwrapFailureCode = fill( """ ThrowInvalidThis(cx, args, %%(securityError)s, "${iface}"); - return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee), - args.rval()); + return ConvertExceptionToPromise(cx, args.rval()); """, iface=descriptor.interface.identifier.name) name = "genericPromiseReturningGetter" - customCallArgs = dedent( - """ - JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - // Make sure to save the callee before someone maybe messes with rval(). - JS::Rooted<JSObject*> callee(cx, &args.callee()); - """) CGAbstractBindingMethod.__init__(self, descriptor, name, JSNativeArguments(), - callArgs=customCallArgs, unwrapFailureCode=unwrapFailureCode) def generate_code(self): return CGGeneric(dedent( """ const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev()); MOZ_ASSERT(info->type() == JSJitInfo::Getter); JSJitGetterOp getter = info->getter; @@ -9238,18 +9218,17 @@ class CGGenericPromiseReturningGetter(CG if (ok) { #ifdef DEBUG AssertReturnTypeMatchesJitinfo(info, args.rval()); #endif return true; } MOZ_ASSERT(info->returnType() == JSVAL_TYPE_OBJECT); - return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee), - args.rval()); + return ConvertExceptionToPromise(cx, args.rval()); """)) class CGSpecializedGetter(CGAbstractStaticMethod): """ A class for generating the code for a specialized attribute getter that the JIT can call with lower overhead. """ @@ -9383,24 +9362,17 @@ class CGGetterPromiseWrapper(CGAbstractS def definition_body(self): return fill( """ bool ok = ${getterName}(${args}); if (ok) { return true; } - JS::Rooted<JSObject*> globalForPromise(cx); - // We can't use xpc::XrayAwareCalleeGlobal here because we have no - // callee. Use our hacky version instead. - if (!xpc::XrayAwareCalleeGlobalForSpecializedGetters(cx, obj, - &globalForPromise)) { - return false; - } - return ConvertExceptionToPromise(cx, globalForPromise, args.rval()); + return ConvertExceptionToPromise(cx, args.rval()); """, getterName=self.getter.name, args=", ".join(arg.name for arg in self.args)) @staticmethod def makeName(getterName): return getterName + "_promiseWrapper"
--- a/dom/bindings/test/TestFunctions.cpp +++ b/dom/bindings/test/TestFunctions.cpp @@ -96,16 +96,23 @@ TestFunctions::TestThrowNsresult(ErrorRe void TestFunctions::TestThrowNsresultFromNative(ErrorResult& aError) { nsCOMPtr<mozITestInterfaceJS> impl = do_CreateInstance("@mozilla.org/dom/test-interface-js;1"); aError = impl->TestThrowNsresultFromNative(); } +already_AddRefed<Promise> +TestFunctions::ThrowToRejectPromise(GlobalObject& aGlobal, ErrorResult& aError) +{ + aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return nullptr; +} + bool TestFunctions::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aWrapper) { return TestFunctionsBinding::Wrap(aCx, this, aGivenProto, aWrapper); } }
--- a/dom/bindings/test/TestFunctions.h +++ b/dom/bindings/test/TestFunctions.h @@ -37,16 +37,19 @@ public: void GetStringDataAsAString(nsAString& aString); void GetStringDataAsAString(uint32_t aLength, nsAString& aString); void GetStringDataAsDOMString(const Optional<uint32_t>& aLength, DOMString& aString); void TestThrowNsresult(ErrorResult& aError); void TestThrowNsresultFromNative(ErrorResult& aError); + static already_AddRefed<Promise> + ThrowToRejectPromise(GlobalObject& aGlobal, + ErrorResult& aError); bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aWrapper); private: nsString mStringData; }; } // namespace dom
--- a/dom/promise/tests/chrome.ini +++ b/dom/promise/tests/chrome.ini @@ -3,8 +3,11 @@ [test_on_new_promise.html] [test_on_promise_settled.html] [test_on_promise_settled_duplicates.html] [test_promise_xrays.html] support-files = file_promise_xrays.html [test_promise_argument_xrays.html] support-files = file_promise_xrays.html file_promise_argument_tests.js skip-if = debug == false +[test_promise_retval_xrays.html] +support-files = file_promise_xrays.html file_promise_retval_tests.js +skip-if = debug == false
--- a/dom/promise/tests/file_promise_argument_tests.js +++ b/dom/promise/tests/file_promise_argument_tests.js @@ -9,17 +9,17 @@ * 3) A function named getPromise. This function is given a global object and a * single argument to use for getting the promise. The getPromise function * is expected to trigger the canonical Promise.resolve for the given global * with the given argument in some way that depends on the test, and return * the result. * 4) A subframe (frames[0]) which can be used as a second global for creating * promises. */ -var label = parent; +var label = "parent"; function passBasicPromise() { var p1 = Promise.resolve(); verifyPromiseGlobal(p1, window, "Promise.resolve return value 1"); var p2 = getPromise(window, p1); is(p1, p2, "Basic promise should just pass on through"); return p2; }
new file mode 100644 --- /dev/null +++ b/dom/promise/tests/file_promise_retval_tests.js @@ -0,0 +1,41 @@ +/* + * This file is meant to provide common infrastructure for several consumers. + * The consumer is expected to define the following things: + * + * 1) A verifyPromiseGlobal function which does whatever test the consumer + * wants. This function is passed a promise and the global whose + * TestFunctions was used to get the promise. + * 2) A expectedExceptionGlobal function which is handed the global whose + * TestFunctions was used to trigger the exception and should return the + * global the exception is expected to live in. + * 3) A subframe (frames[0]) which can be used as a second global for creating + * promises. + */ +var label = "parent"; + +function testThrownException(global) { + var p = global.TestFunctions.throwToRejectPromise(); + verifyPromiseGlobal(p, global, "throwToRejectPromise return value"); + return p.then(() => {}).catch((err) => { + var expected = expectedExceptionGlobal(global) + is(SpecialPowers.unwrap(SpecialPowers.Cu.getGlobalForObject(err)), + expected, + "Should have an exception object from the right global too"); + ok(err instanceof expected.DOMException, + "Should have a DOMException here"); + is(Object.getPrototypeOf(err), expected.DOMException.prototype, + "Should have a DOMException from the right global"); + is(err.name, "InvalidStateError", "Should have the right DOMException"); + }); +} + +function runPromiseRetvalTests(finishFunc) { + Promise.resolve() + .then(testThrownException.bind(undefined, window)) + .then(testThrownException.bind(undefined, frames[0])) + .then(finishFunc) + .catch(function(e) { + ok(false, `Exception thrown: ${e}@${location.pathname}:${e.lineNumber}:${e.columnNumber}`); + finishFunc(); + }); +}
--- a/dom/promise/tests/mochitest.ini +++ b/dom/promise/tests/mochitest.ini @@ -18,8 +18,11 @@ support-files = file_promise_and_timeout [test_webassembly_compile.html] support-files = test_webassembly_compile_sample.wasm test_webassembly_compile_worker.js test_webassembly_compile_worker_terminate.js [test_promise_argument.html] support-files = file_promise_argument_tests.js skip-if = debug == false [test_promise_callback_retval.html] support-files = file_promise_argument_tests.js skip-if = debug == false +[test_promise_retval.html] +support-files = file_promise_retval_tests.js +skip-if = debug == false
--- a/dom/promise/tests/test_promise_argument_xrays.html +++ b/dom/promise/tests/test_promise_argument_xrays.html @@ -74,16 +74,17 @@ function nextTest() { if (tests.length == 0) { SimpleTest.finish(); return; } tests.shift()(); } addLoadEvent(function() { + frames[0].label = "child"; SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, nextTest); }); </script> </pre> </body> </html>
copy from dom/promise/tests/test_promise_argument.html copy to dom/promise/tests/test_promise_retval.html --- a/dom/promise/tests/test_promise_argument.html +++ b/dom/promise/tests/test_promise_retval.html @@ -1,43 +1,45 @@ <!DOCTYPE HTML> <html> <!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=1323324 +https://bugzilla.mozilla.org/show_bug.cgi?id=1436276. --> <head> <meta charset="utf-8"> - <title>Test for Bug 1323324</title> + <title>Test for Bug 1436276.</title> <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> - <script src="file_promise_argument_tests.js"></script> + <script src="file_promise_retval_tests.js"></script> <script type="application/javascript"> - /** Test for Bug 1323324 **/ + /** Test for Bug 1436276. **/ SimpleTest.waitForExplicitFinish(); - var globalWrapper; function verifyPromiseGlobal(p, global, msg) { // SpecialPowers.Cu.getGlobalForObject returns a SpecialPowers wrapper for // the actual global. We want to grab the underlying object. - globalWrapper = SpecialPowers.Cu.getGlobalForObject(p); + var globalWrapper = SpecialPowers.Cu.getGlobalForObject(p); is(SpecialPowers.unwrap(globalWrapper), global, msg + " should come from " + global.label); } - const isXrayArgumentTest = false; + function expectedExceptionGlobal(global) { + // We should end up with an exception from "global". + return global; + } function getPromise(global, arg) { return global.TestFunctions.passThroughPromise(arg); } addLoadEvent(function() { frames[0].label = "child"; SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, - runPromiseArgumentTests.bind(undefined, - SimpleTest.finish)); + runPromiseRetvalTests.bind(undefined, + SimpleTest.finish)); }); </script> </head> <body> <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1323324">Mozilla Bug 1323324</a> <p id="display"></p> <div id="content" style="display: none"> <!-- A subframe so we have another global to work with -->
copy from dom/promise/tests/test_promise_argument_xrays.html copy to dom/promise/tests/test_promise_retval_xrays.html --- a/dom/promise/tests/test_promise_argument_xrays.html +++ b/dom/promise/tests/test_promise_retval_xrays.html @@ -1,29 +1,29 @@ <!DOCTYPE HTML> <html> <!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=1233324 +https://bugzilla.mozilla.org/show_bug.cgi?id=1436276. --> <head> <meta charset="utf-8"> - <title>Test for Bug 1233324</title> + <title>Test for Bug 1436276.</title> <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> <link rel="stylesheet" type="text/css" href="chrome://global/skin"/> <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/> </head> <body> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1233324">Mozilla Bug 1233324</a> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1436276.">Mozilla Bug 1436276.</a> <p id="display"></p> <div id="content" style="display: none"> <iframe id="t" src="http://example.org/chrome/dom/promise/tests/file_promise_xrays.html"></iframe> </div> <pre id="test"> -<script src="file_promise_argument_tests.js"></script> +<script src="file_promise_retval_tests.js"></script> <script type="application/javascript"> var win = $("t").contentWindow; /** Test for Bug 1233324 **/ SimpleTest.waitForExplicitFinish(); function testLoadComplete() { @@ -49,41 +49,46 @@ function verifyPromiseGlobal(p, _, msg) // the actual global. We want to grab the underlying object. var global = SpecialPowers.unwrap(SpecialPowers.Cu.getGlobalForObject(p)); // We expect our global to always be "window" here, because we're working over // Xrays. is(global, window, msg + " should come from " + window.label); } -const isXrayArgumentTest = true; +function expectedExceptionGlobal(_) { + // We should end up with an exception from "window" no matter what global + // was involved to start with, because we're working over Xrays. + return window; +} function getPromise(global, arg) { return global.TestFunctions.passThroughPromise(arg); } -function testPromiseArgumentConversions() { - runPromiseArgumentTests(nextTest); +function testPromiseRetvals() { + runPromiseRetvalTests(nextTest); } var tests = [ testLoadComplete, testHaveXray, - testPromiseArgumentConversions, + testPromiseRetvals, ]; function nextTest() { if (tests.length == 0) { SimpleTest.finish(); return; } tests.shift()(); } addLoadEvent(function() { + frames[0].label = "child"; SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, nextTest); }); </script> </pre> </body> </html>
--- a/dom/webidl/TestFunctions.webidl +++ b/dom/webidl/TestFunctions.webidl @@ -39,9 +39,13 @@ interface TestFunctions { // stringbuffers. If length not passed, use our full length. DOMString getStringDataAsDOMString(optional unsigned long length); // Functions that just punch through to mozITestInterfaceJS.idl [Throws] void testThrowNsresult(); [Throws] void testThrowNsresultFromNative(); + + // Throws an InvalidStateError to auto-create a rejected promise. + [Throws] + static Promise<any> throwToRejectPromise(); };
--- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -309,22 +309,21 @@ SandboxFetch(JSContext* cx, JS::HandleOb args.rval().setObject(*response->PromiseObj()); return true; } static bool SandboxFetchPromise(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); - RootedObject callee(cx, &args.callee()); RootedObject scope(cx, JS::CurrentGlobalOrNull(cx)); if (SandboxFetch(cx, scope, args)) { return true; } - return ConvertExceptionToPromise(cx, scope, args.rval()); + return ConvertExceptionToPromise(cx, args.rval()); } static bool SandboxCreateFetch(JSContext* cx, HandleObject obj) { MOZ_ASSERT(JS_IsGlobalObject(obj));