diff --git a/devtools/server/actors/script.js b/devtools/server/actors/script.js index d5aa32479803..2dc1a1bcbc67 100644 --- a/devtools/server/actors/script.js +++ b/devtools/server/actors/script.js @@ -19,7 +19,6 @@ const { ActorClassWithSpec } = require("devtools/shared/protocol"); const DevToolsUtils = require("devtools/shared/DevToolsUtils"); const { assert, dumpn, update, fetch } = DevToolsUtils; const promise = require("promise"); -const PromiseDebugging = require("PromiseDebugging"); const xpcInspector = require("xpcInspector"); const ScriptStore = require("./utils/ScriptStore"); const { DevToolsWorker } = require("devtools/shared/worker/worker"); diff --git a/devtools/shared/worker/loader.js b/devtools/shared/worker/loader.js index 9994b0a3cbac..973354de341a 100644 --- a/devtools/shared/worker/loader.js +++ b/devtools/shared/worker/loader.js @@ -317,12 +317,6 @@ this.WorkerDebuggerLoader = WorkerDebuggerLoader; // does not provide alternative definitions for them. Consequently, they are // stubbed out both on the main thread and worker threads. -var PromiseDebugging = { - getState: function () { - throw new Error("PromiseDebugging is not available in workers!"); - } -}; - var chrome = { CC: undefined, Cc: undefined, @@ -496,7 +490,6 @@ this.worker = new WorkerDebuggerLoader({ loadSubScript: loadSubScript, modules: { "Debugger": Debugger, - "PromiseDebugging": PromiseDebugging, "Services": Object.create(null), "chrome": chrome, "xpcInspector": xpcInspector diff --git a/docshell/test/browser/browser_timelineMarkers-frame-04.js b/docshell/test/browser/browser_timelineMarkers-frame-04.js index 34dc26075f24..427312993fff 100644 --- a/docshell/test/browser/browser_timelineMarkers-frame-04.js +++ b/docshell/test/browser/browser_timelineMarkers-frame-04.js @@ -50,7 +50,11 @@ if (Services.prefs.getBoolPref("javascript.options.asyncstack")) { ok(frame.asyncParent !== null, "Parent frame has async parent"); is(frame.asyncParent.asyncCause, "promise callback", "Async parent has correct cause"); - is(frame.asyncParent.functionDisplayName, "do_promise", + let asyncFrame = frame.asyncParent; + // Skip over self-hosted parts of our Promise implementation. + while (asyncFrame.source === 'self-hosted') + asyncFrame = asyncFrame.parent; + is(asyncFrame.functionDisplayName, "do_promise", "Async parent has correct function name"); } }, { @@ -71,7 +75,11 @@ if (Services.prefs.getBoolPref("javascript.options.asyncstack")) { ok(frame.asyncParent !== null, "Parent frame has async parent"); is(frame.asyncParent.asyncCause, "promise callback", "Async parent has correct cause"); - is(frame.asyncParent.functionDisplayName, "do_promise_script", + let asyncFrame = frame.asyncParent; + // Skip over self-hosted parts of our Promise implementation. + while (asyncFrame.source === 'self-hosted') + asyncFrame = asyncFrame.parent; + is(asyncFrame.functionDisplayName, "do_promise_script", "Async parent has correct function name"); } }); diff --git a/docshell/test/browser/browser_timelineMarkers-frame-05.js b/docshell/test/browser/browser_timelineMarkers-frame-05.js index 827eb716ccb0..713f0e5604a0 100644 --- a/docshell/test/browser/browser_timelineMarkers-frame-05.js +++ b/docshell/test/browser/browser_timelineMarkers-frame-05.js @@ -91,12 +91,24 @@ if (Services.prefs.getBoolPref("javascript.options.asyncstack")) { check: function(markers) { markers = markers.filter(m => m.name == "ConsoleTime"); ok(markers.length > 0, "Promise marker includes stack"); - + ok(markers[0].stack.functionDisplayName == "testConsoleTime", + "testConsoleTime is on the stack"); let frame = markers[0].endStack; - ok(frame.parent.asyncParent !== null, "Parent frame has async parent"); - is(frame.parent.asyncParent.asyncCause, "promise callback", + ok(frame.functionDisplayName == "testConsoleTimeEnd", + "testConsoleTimeEnd is on the stack"); + + frame = frame.parent; + ok(frame.functionDisplayName == "makePromise/<", + "makePromise/< is on the stack"); + let asyncFrame = frame.asyncParent; + ok(asyncFrame !== null, "Frame has async parent"); + is(asyncFrame.asyncCause, "promise callback", "Async parent has correct cause"); - is(frame.parent.asyncParent.functionDisplayName, "makePromise", + // Skip over self-hosted parts of our Promise implementation. + while (asyncFrame.source === 'self-hosted') { + asyncFrame = asyncFrame.parent; + } + is(asyncFrame.functionDisplayName, "makePromise", "Async parent has correct function name"); } }); diff --git a/dom/bindings/test/test_promise_rejections_from_jsimplemented.html b/dom/bindings/test/test_promise_rejections_from_jsimplemented.html index 187922474235..5428030c574a 100644 --- a/dom/bindings/test/test_promise_rejections_from_jsimplemented.html +++ b/dom/bindings/test/test_promise_rejections_from_jsimplemented.html @@ -25,7 +25,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1107592 "Should have the right message in test " + testNumber); is(exn.code, code, "Should have the right .code in test " + testNumber); if (message === "") { - is(exn.name, "NS_ERROR_UNEXPECTED", + is(exn.name, "InternalError", "Should have one of our synthetic exceptions in test " + testNumber); } is(exn.stack, stack, "Should have the right stack in test " + testNumber); @@ -41,79 +41,88 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1107592 var isE10S = !SpecialPowers.isMainProcess(); var asyncStack = SpecialPowers.getBoolPref("javascript.options.asyncstack"); var ourFile = location.href; - var parentFrame = (asyncStack && !isE10S) ? `Async*@${ourFile}:121:3 + var unwrapError = "Promise rejection value is a non-unwrappable cross-compartment wrapper."; + var parentFrame = (asyncStack && !isE10S) ? `Async*@${ourFile}:130:3 ` : ""; Promise.all([ t.testPromiseWithThrowingChromePromiseInit().then( ensurePromiseFail.bind(null, 1), - checkExn.bind(null, 48, "NS_ERROR_UNEXPECTED", "", undefined, - ourFile, 1, - `doTest@${ourFile}:48:7 + checkExn.bind(null, 49, "InternalError", unwrapError, + undefined, ourFile, 1, + `doTest@${ourFile}:49:7 ` + parentFrame)), t.testPromiseWithThrowingContentPromiseInit(function() { thereIsNoSuchContentFunction1(); }).then( ensurePromiseFail.bind(null, 2), - checkExn.bind(null, 56, "ReferenceError", + checkExn.bind(null, 57, "ReferenceError", "thereIsNoSuchContentFunction1 is not defined", undefined, ourFile, 2, - `doTest/<@${ourFile}:56:11 -doTest@${ourFile}:55:7 + `doTest/<@${ourFile}:57:11 +doTest@${ourFile}:56:7 ` + parentFrame)), t.testPromiseWithThrowingChromeThenFunction().then( ensurePromiseFail.bind(null, 3), - checkExn.bind(null, 0, "NS_ERROR_UNEXPECTED", "", undefined, "", 3, "")), + checkExn.bind(null, 0, "InternalError", unwrapError, undefined, "", 3, asyncStack ? (`Async*doTest@${ourFile}:67:7 +` + + parentFrame) : "")), t.testPromiseWithThrowingContentThenFunction(function() { thereIsNoSuchContentFunction2(); }).then( ensurePromiseFail.bind(null, 4), - checkExn.bind(null, 70, "ReferenceError", + checkExn.bind(null, 73, "ReferenceError", "thereIsNoSuchContentFunction2 is not defined", undefined, ourFile, 4, - `doTest/<@${ourFile}:70:11 + `doTest/<@${ourFile}:73:11 ` + - (asyncStack ? `Async*doTest@${ourFile}:69:7 + (asyncStack ? `Async*doTest@${ourFile}:72:7 ` : "") + parentFrame)), t.testPromiseWithThrowingChromeThenable().then( ensurePromiseFail.bind(null, 5), - checkExn.bind(null, 0, "NS_ERROR_UNEXPECTED", "", undefined, "", 5, "")), + checkExn.bind(null, 0, "InternalError", unwrapError, undefined, "", 5, asyncStack ? (`Async*doTest@${ourFile}:84:7 +` + + parentFrame) : "")), t.testPromiseWithThrowingContentThenable({ then: function() { thereIsNoSuchContentFunction3(); } }).then( ensurePromiseFail.bind(null, 6), - checkExn.bind(null, 85, "ReferenceError", + checkExn.bind(null, 90, "ReferenceError", "thereIsNoSuchContentFunction3 is not defined", undefined, ourFile, 6, - `doTest/<.then@${ourFile}:85:32 -`)), + `doTest/<.then@${ourFile}:90:32 +` + (asyncStack ? `Async*doTest@${ourFile}:89:7\n` + parentFrame : ""))), t.testPromiseWithDOMExceptionThrowingPromiseInit().then( ensurePromiseFail.bind(null, 7), - checkExn.bind(null, 93, "NotFoundError", + checkExn.bind(null, 98, "NotFoundError", "We are a second DOMException", DOMException.NOT_FOUND_ERR, ourFile, 7, - `doTest@${ourFile}:93:7 + `doTest@${ourFile}:98:7 ` + parentFrame)), t.testPromiseWithDOMExceptionThrowingThenFunction().then( ensurePromiseFail.bind(null, 8), - checkExn.bind(null, asyncStack ? 101 : 0, "NetworkError", + checkExn.bind(null, asyncStack ? 106 : 0, "NetworkError", "We are a third DOMException", DOMException.NETWORK_ERR, asyncStack ? ourFile : "", 8, - (asyncStack ? `Async*doTest@${ourFile}:101:7 + (asyncStack ? `Async*doTest@${ourFile}:106:7 ` + parentFrame : ""))), t.testPromiseWithDOMExceptionThrowingThenable().then( ensurePromiseFail.bind(null, 9), - checkExn.bind(null, 0, "TypeMismatchError", + checkExn.bind(null, asyncStack ? 114 : 0, "TypeMismatchError", "We are a fourth DOMException", - DOMException.TYPE_MISMATCH_ERR, "", 9, "")), + DOMException.TYPE_MISMATCH_ERR, + asyncStack ? ourFile : "", 9, + (asyncStack ? `Async*doTest@${ourFile}:114:7 +` + + parentFrame : ""))), ]).then(SimpleTest.finish, - function() { - ok(false, "One of our catch statements totally failed"); + function(err) { + ok(false, "One of our catch statements totally failed with err" + err + ', stack: ' + (err ? err.stack : '')); SimpleTest.finish(); }); } diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html index 4efd2567deb5..23952ddbd7f2 100644 --- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -72,6 +72,7 @@ var ecmaGlobals = {name: "NaN", xbl: false}, "Number", "Object", + "Promise", "Proxy", "RangeError", "ReferenceError", @@ -961,8 +962,6 @@ var interfaceNamesInGlobalScope = "ProcessingInstruction", // IMPORTANT: Do not change this list without review from a DOM peer! "ProgressEvent", -// IMPORTANT: Do not change this list without review from a DOM peer! - "Promise", // IMPORTANT: Do not change this list without review from a DOM peer! {name: "PushManager", b2g: false}, // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js index c084a75f07ae..85d3ac8ce6d1 100644 --- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js +++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js @@ -47,6 +47,7 @@ var ecmaGlobals = "NaN", "Number", "Object", + "Promise", "Proxy", "RangeError", "ReferenceError", @@ -174,8 +175,6 @@ var interfaceNamesInGlobalScope = { name: "PerformanceObserver", nightly: true }, // IMPORTANT: Do not change this list without review from a DOM peer! { name: "PerformanceObserverEntryList", nightly: true }, -// IMPORTANT: Do not change this list without review from a DOM peer! - "Promise", // IMPORTANT: Do not change this list without review from a DOM peer! { name: "PushEvent", b2g: false }, // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/workers/test/test_worker_interfaces.js b/dom/workers/test/test_worker_interfaces.js index 2122751e3aa6..c33a9f17bef9 100644 --- a/dom/workers/test/test_worker_interfaces.js +++ b/dom/workers/test/test_worker_interfaces.js @@ -47,6 +47,7 @@ var ecmaGlobals = "NaN", "Number", "Object", + "Promise", "Proxy", "RangeError", "ReferenceError", @@ -166,8 +167,6 @@ var interfaceNamesInGlobalScope = { name: "PerformanceObserver", nightly: true }, // IMPORTANT: Do not change this list without review from a DOM peer! { name: "PerformanceObserverEntryList", nightly: true }, -// IMPORTANT: Do not change this list without review from a DOM peer! - "Promise", // IMPORTANT: Do not change this list without review from a DOM peer! { name: "PushManager", b2g: false }, // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/js/moz.configure b/js/moz.configure index 3d9a87e328f3..0511a6d4fe0a 100644 --- a/js/moz.configure +++ b/js/moz.configure @@ -39,7 +39,8 @@ set_config('JS_DISABLE_SHELL', js_disable_shell) # Use SpiderMonkey Promise implementation if it's enabled # ======================================================= -js_option('--enable-sm-promise', help='Enable SpiderMonkey promises') +js_option('--enable-sm-promise', default=True, + help='Enable SpiderMonkey promises') @depends('--enable-sm-promise') def sm_promise(value): diff --git a/js/src/jit-test/lib/debuggerNXHelper.js b/js/src/jit-test/lib/debuggerNXHelper.js index 6976a3aab962..61792da84d07 100644 --- a/js/src/jit-test/lib/debuggerNXHelper.js +++ b/js/src/jit-test/lib/debuggerNXHelper.js @@ -32,14 +32,16 @@ function testDebuggerHooksNX(dbg, g, testHook) { testDebuggerHook("onNewGlobalObject", () => { newGlobal(); }); - testDebuggerHook("onNewPromise", - () => { g.makeFakePromise(); }); + if ('Promise' in g) { + testDebuggerHook("onNewPromise", + () => { new g.Promise(()=>{}); }); - testDebuggerHook("onPromiseSettled", - () => { - var p = g.makeFakePromise(); - g.settleFakePromise(p); - }); + testDebuggerHook("onPromiseSettled", + () => { + var p = new g.Promise(()=>{}); + g.settlePromiseNow(p); + }); + } // Hooks on frames. var onStepHit = false; diff --git a/js/src/jit-test/tests/debug/Debugger-onNewPromise-01.js b/js/src/jit-test/tests/debug/Debugger-onNewPromise-01.js index a76f0018ab5d..07081168cd99 100644 --- a/js/src/jit-test/tests/debug/Debugger-onNewPromise-01.js +++ b/js/src/jit-test/tests/debug/Debugger-onNewPromise-01.js @@ -1,5 +1,7 @@ // Test that the onNewPromise hook gets called when promises are allocated in // the scope of debuggee globals. +if (!('Promise' in this)) + quit(0); var g = newGlobal(); var dbg = new Debugger(); @@ -9,9 +11,9 @@ var gw = dbg.addDebuggee(g); let promisesFound = []; dbg.onNewPromise = p => { promisesFound.push(p); }; -let p1 = g.makeFakePromise() +let p1 = new g.Promise(function (){}); dbg.enabled = false; -let p2 = g.makeFakePromise(); +let p2 = new g.Promise(function (){}); assertEq(promisesFound.indexOf(gw.makeDebuggeeValue(p1)) != -1, true); assertEq(promisesFound.indexOf(gw.makeDebuggeeValue(p2)) == -1, true); diff --git a/js/src/jit-test/tests/debug/Debugger-onNewPromise-02.js b/js/src/jit-test/tests/debug/Debugger-onNewPromise-02.js index ebaf8254027e..21db892d8f82 100644 --- a/js/src/jit-test/tests/debug/Debugger-onNewPromise-02.js +++ b/js/src/jit-test/tests/debug/Debugger-onNewPromise-02.js @@ -1,11 +1,13 @@ // onNewPromise handlers fire, until they are removed. +if (!('Promise' in this)) + quit(0); var g = newGlobal(); var dbg = new Debugger(g); var log; log = ''; -g.makeFakePromise(); +new g.Promise(function (){}); assertEq(log, ''); dbg.onNewPromise = function (promise) { @@ -15,10 +17,10 @@ dbg.onNewPromise = function (promise) { }; log = ''; -g.makeFakePromise(); +new g.Promise(function (){}); assertEq(log, 'n'); log = ''; dbg.onNewPromise = undefined; -g.makeFakePromise(); +new g.Promise(function (){}); assertEq(log, ''); diff --git a/js/src/jit-test/tests/debug/Debugger-onNewPromise-03.js b/js/src/jit-test/tests/debug/Debugger-onNewPromise-03.js index 118453e1cad1..377855a1fe8a 100644 --- a/js/src/jit-test/tests/debug/Debugger-onNewPromise-03.js +++ b/js/src/jit-test/tests/debug/Debugger-onNewPromise-03.js @@ -1,4 +1,6 @@ // onNewPromise handlers on different Debugger instances are independent. +if (!('Promise' in this)) + quit(0); var g = newGlobal(); var dbg1 = new Debugger(g); @@ -18,24 +20,24 @@ function h2(promise) { } log1 = log2 = ''; -g.makeFakePromise(); +new g.Promise(function (){}); assertEq(log1, ''); assertEq(log2, ''); log1 = log2 = ''; dbg1.onNewPromise = h1; -g.makeFakePromise(); +new g.Promise(function (){}); assertEq(log1, 'n'); assertEq(log2, ''); log1 = log2 = ''; dbg2.onNewPromise = h2; -g.makeFakePromise(); +new g.Promise(function (){}); assertEq(log1, 'n'); assertEq(log2, 'n'); log1 = log2 = ''; dbg1.onNewPromise = undefined; -g.makeFakePromise(); +new g.Promise(function (){}); assertEq(log1, ''); assertEq(log2, 'n'); diff --git a/js/src/jit-test/tests/debug/Debugger-onNewPromise-04.js b/js/src/jit-test/tests/debug/Debugger-onNewPromise-04.js index 3d8845711a6a..410a0add9d5c 100644 --- a/js/src/jit-test/tests/debug/Debugger-onNewPromise-04.js +++ b/js/src/jit-test/tests/debug/Debugger-onNewPromise-04.js @@ -1,4 +1,6 @@ // An onNewPromise handler can disable itself. +if (!('Promise' in this)) + quit(0); var g = newGlobal(); var dbg = new Debugger(g); @@ -10,6 +12,6 @@ dbg.onNewPromise = function (promise) { }; log = ''; -g.makeFakePromise(); -g.makeFakePromise(); +new g.Promise(function (){}); +new g.Promise(function (){}); assertEq(log, 'n'); diff --git a/js/src/jit-test/tests/debug/Debugger-onNewPromise-05.js b/js/src/jit-test/tests/debug/Debugger-onNewPromise-05.js index 9091192fe0ba..29edfeeddd8b 100644 --- a/js/src/jit-test/tests/debug/Debugger-onNewPromise-05.js +++ b/js/src/jit-test/tests/debug/Debugger-onNewPromise-05.js @@ -1,8 +1,11 @@ // Creating a promise within an onNewPromise handler causes a recursive handler // invocation. +if (!('Promise' in this)) + quit(0); var g = newGlobal(); -var dbg = new Debugger(g); +var dbg = new Debugger(); +var gw = dbg.addDebuggee(g); var log; var depth; @@ -13,12 +16,12 @@ dbg.onNewPromise = function (promise) { promise.seen = true; if (depth < 3) - g.makeFakePromise(); + gw.executeInGlobal(`new Promise(_=>{})`); log += ')'; depth--; }; log = ''; depth = 0; -g.makeFakePromise(); +new g.Promise(function (){}); assertEq(log, '((()))'); diff --git a/js/src/jit-test/tests/debug/Debugger-onNewPromise-06.js b/js/src/jit-test/tests/debug/Debugger-onNewPromise-06.js index 4819d8ef5e56..7e5b9927a318 100644 --- a/js/src/jit-test/tests/debug/Debugger-onNewPromise-06.js +++ b/js/src/jit-test/tests/debug/Debugger-onNewPromise-06.js @@ -1,4 +1,6 @@ // Resumption values from onNewPromise handlers are disallowed. +if (!('Promise' in this)) + quit(0); load(libdir + 'asserts.js'); @@ -8,28 +10,28 @@ var log; dbg.onNewPromise = function (g) { log += 'n'; return undefined; }; log = ''; -assertEq(typeof g.makeFakePromise(), "object"); +assertEq(typeof new g.Promise(function (){}), "object"); assertEq(log, 'n'); dbg.uncaughtExceptionHook = function (ex) { assertEq(/disallowed/.test(ex), true); log += 'u'; } dbg.onNewPromise = function (g) { log += 'n'; return { return: "snoo" }; }; log = ''; -assertEq(typeof g.makeFakePromise(), "object"); +assertEq(typeof new g.Promise(function (){}), "object"); assertEq(log, 'nu'); dbg.onNewPromise = function (g) { log += 'n'; return { throw: "snoo" }; }; log = ''; -assertEq(typeof g.makeFakePromise(), "object"); +assertEq(typeof new g.Promise(function (){}), "object"); assertEq(log, 'nu'); dbg.onNewPromise = function (g) { log += 'n'; return null; }; log = ''; -assertEq(typeof g.makeFakePromise(), "object"); +assertEq(typeof new g.Promise(function (){}), "object"); assertEq(log, 'nu'); dbg.uncaughtExceptionHook = function (ex) { assertEq(/foopy/.test(ex), true); log += 'u'; } dbg.onNewPromise = function (g) { log += 'n'; throw "foopy"; }; log = ''; -assertEq(typeof g.makeFakePromise(), "object"); +assertEq(typeof new g.Promise(function (){}), "object"); assertEq(log, 'nu'); diff --git a/js/src/jit-test/tests/debug/Debugger-onNewPromise-07.js b/js/src/jit-test/tests/debug/Debugger-onNewPromise-07.js index d97cd30859ed..495f356c6354 100644 --- a/js/src/jit-test/tests/debug/Debugger-onNewPromise-07.js +++ b/js/src/jit-test/tests/debug/Debugger-onNewPromise-07.js @@ -1,5 +1,7 @@ // Errors in onNewPromise handlers are reported correctly, and don't mess up the // promise creation. +if (!('Promise' in this)) + quit(0); var g = newGlobal(); var dbg = new Debugger(g); @@ -8,6 +10,6 @@ let e; dbg.uncaughtExceptionHook = ee => { e = ee; }; dbg.onNewPromise = () => { throw new Error("woops!"); }; -assertEq(typeof g.makeFakePromise(), "object"); +assertEq(typeof new g.Promise(function (){}), "object"); assertEq(!!e, true); assertEq(!!e.message.match(/woops/), true); diff --git a/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-01.js b/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-01.js index c228c60bed65..7277ed8ae3fb 100644 --- a/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-01.js +++ b/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-01.js @@ -1,4 +1,6 @@ // Test that the onPromiseSettled hook gets called when a promise settles. +if (!('Promise' in this)) + quit(0); var g = newGlobal(); var dbg = new Debugger(); @@ -11,15 +13,15 @@ dbg.onPromiseSettled = pw_ => { log += "s"; }; -let p = g.makeFakePromise(); -g.settleFakePromise(p); +let p = new g.Promise(function (){}); +g.settlePromiseNow(p); assertEq(log, "s"); assertEq(pw, gw.makeDebuggeeValue(p)); log = ""; dbg.enabled = false; -p = g.makeFakePromise(); -g.settleFakePromise(p); +p = new g.Promise(function (){}); +g.settlePromiseNow(p); assertEq(log, ""); diff --git a/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-02.js b/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-02.js index 42d810a71525..febca8f78bae 100644 --- a/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-02.js +++ b/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-02.js @@ -1,11 +1,13 @@ // onPromiseSettled handlers fire, until they are removed. +if (!('Promise' in this)) + quit(0); var g = newGlobal(); var dbg = new Debugger(g); var log; log = ''; -g.settleFakePromise(g.makeFakePromise()); +g.settlePromiseNow(new g.Promise(function (){})); assertEq(log, ''); dbg.onPromiseSettled = function (promise) { @@ -15,10 +17,10 @@ dbg.onPromiseSettled = function (promise) { }; log = ''; -g.settleFakePromise(g.makeFakePromise()); +g.settlePromiseNow(new g.Promise(function (){})); assertEq(log, 's'); log = ''; dbg.onPromiseSettled = undefined; -g.settleFakePromise(g.makeFakePromise()); +g.settlePromiseNow(new g.Promise(function (){})); assertEq(log, ''); diff --git a/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-03.js b/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-03.js index d37e90c5dd4c..34e9f241780f 100644 --- a/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-03.js +++ b/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-03.js @@ -1,4 +1,6 @@ // onPromiseSettled handlers on different Debugger instances are independent. +if (!('Promise' in this)) + quit(0); var g = newGlobal(); var dbg1 = new Debugger(g); @@ -18,24 +20,24 @@ function h2(promise) { } log1 = log2 = ''; -g.settleFakePromise(g.makeFakePromise()); +g.settlePromiseNow(new g.Promise(function (){})); assertEq(log1, ''); assertEq(log2, ''); log1 = log2 = ''; dbg1.onPromiseSettled = h1; -g.settleFakePromise(g.makeFakePromise()); +g.settlePromiseNow(new g.Promise(function (){})); assertEq(log1, 's'); assertEq(log2, ''); log1 = log2 = ''; dbg2.onPromiseSettled = h2; -g.settleFakePromise(g.makeFakePromise()); +g.settlePromiseNow(new g.Promise(function (){})); assertEq(log1, 's'); assertEq(log2, 's'); log1 = log2 = ''; dbg1.onPromiseSettled = undefined; -g.settleFakePromise(g.makeFakePromise()); +g.settlePromiseNow(new g.Promise(function (){})); assertEq(log1, ''); assertEq(log2, 's'); diff --git a/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-04.js b/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-04.js index 0ffe4fd1a7da..86df066c87f4 100644 --- a/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-04.js +++ b/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-04.js @@ -1,4 +1,6 @@ // An onPromiseSettled handler can disable itself. +if (!('Promise' in this)) + quit(0); var g = newGlobal(); var dbg = new Debugger(g); @@ -10,6 +12,6 @@ dbg.onPromiseSettled = function (promise) { }; log = ''; -g.settleFakePromise(g.makeFakePromise()); -g.settleFakePromise(g.makeFakePromise()); +g.settlePromiseNow(new g.Promise(function (){})); +g.settlePromiseNow(new g.Promise(function (){})); assertEq(log, 's'); diff --git a/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-05.js b/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-05.js index 1dd6792621bb..da358efe8ed8 100644 --- a/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-05.js +++ b/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-05.js @@ -1,8 +1,11 @@ // Settling a promise within an onPromiseSettled handler causes a recursive // handler invocation. +if (!('Promise' in this)) + quit(0); var g = newGlobal(); -var dbg = new Debugger(g); +var dbg = new Debugger(); +var gw = dbg.addDebuggee(g); var log; var depth; @@ -12,13 +15,13 @@ dbg.onPromiseSettled = function (promise) { assertEq(promise.seen, undefined); promise.seen = true; - if (depth < 3) - g.settleFakePromise(g.makeFakePromise()); - + if (depth < 3) { + gw.executeInGlobal(`settlePromiseNow(new Promise(_=>{}));`); + } log += ')'; depth--; }; log = ''; depth = 0; -g.settleFakePromise(g.makeFakePromise()); +g.settlePromiseNow(new g.Promise(_=>{})); assertEq(log, '((()))'); diff --git a/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-06.js b/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-06.js index e8f481462a58..97108bef4437 100644 --- a/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-06.js +++ b/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-06.js @@ -1,4 +1,6 @@ // Resumption values from onPromiseSettled handlers are disallowed. +if (!('Promise' in this)) + quit(0); load(libdir + 'asserts.js'); @@ -8,28 +10,28 @@ var log; dbg.onPromiseSettled = function (g) { log += 's'; return undefined; }; log = ''; -g.settleFakePromise(g.makeFakePromise()); +g.settlePromiseNow(new g.Promise(function (){})); assertEq(log, 's'); dbg.uncaughtExceptionHook = function (ex) { assertEq(/disallowed/.test(ex), true); log += 'u'; } dbg.onPromiseSettled = function (g) { log += 's'; return { return: "snoo" }; }; log = ''; -g.settleFakePromise(g.makeFakePromise()); +g.settlePromiseNow(new g.Promise(function (){})); assertEq(log, 'su'); dbg.onPromiseSettled = function (g) { log += 's'; return { throw: "snoo" }; }; log = ''; -g.settleFakePromise(g.makeFakePromise()); +g.settlePromiseNow(new g.Promise(function (){})); assertEq(log, 'su'); dbg.onPromiseSettled = function (g) { log += 's'; return null; }; log = ''; -g.settleFakePromise(g.makeFakePromise()); +g.settlePromiseNow(new g.Promise(function (){})); assertEq(log, 'su'); dbg.uncaughtExceptionHook = function (ex) { assertEq(/foopy/.test(ex), true); log += 'u'; } dbg.onPromiseSettled = function (g) { log += 's'; throw "foopy"; }; log = ''; -g.settleFakePromise(g.makeFakePromise()); +g.settlePromiseNow(new g.Promise(function (){})); assertEq(log, 'su'); diff --git a/js/src/jit-test/tests/debug/Memory-drainAllocationsLog-15.js b/js/src/jit-test/tests/debug/Memory-drainAllocationsLog-15.js index 197642868bef..471e8ce39bf6 100644 --- a/js/src/jit-test/tests/debug/Memory-drainAllocationsLog-15.js +++ b/js/src/jit-test/tests/debug/Memory-drainAllocationsLog-15.js @@ -1,4 +1,6 @@ // Test drainAllocationsLog() and [[Class]] names. +if (!('Promise' in this)) + quit(0); const root = newGlobal(); const dbg = new Debugger(); @@ -12,7 +14,7 @@ root.eval( { expected: "Date", test: () => new Date }, { expected: "RegExp", test: () => /problems/ }, { expected: "Int8Array", test: () => new Int8Array }, - { expected: "Promise", test: makeFakePromise }, + { expected: "Promise", test: () => new Promise(function (){})}, ]; ` ); diff --git a/js/src/jit-test/tests/debug/bug-1102549.js b/js/src/jit-test/tests/debug/bug-1102549.js index bf88ef3f3829..d7bb893f282b 100644 --- a/js/src/jit-test/tests/debug/bug-1102549.js +++ b/js/src/jit-test/tests/debug/bug-1102549.js @@ -1,5 +1,9 @@ // |jit-test| error: log is not defined + +if (!this.Promise) + throw new Error('log is not defined'); + var g = newGlobal(); var dbg = new Debugger(g); dbg.onPromiseSettled = function (g) { log += 's'; throw "foopy"; }; -g.settleFakePromise(g.makeFakePromise()); +g.settlePromiseNow(new g.Promise(function (){})); diff --git a/js/src/jsapi-tests/testPromise.cpp b/js/src/jsapi-tests/testPromise.cpp index 0df22f7fc4c7..45b9eb12da31 100644 --- a/js/src/jsapi-tests/testPromise.cpp +++ b/js/src/jsapi-tests/testPromise.cpp @@ -16,7 +16,9 @@ static bool executor_called = false; static bool PromiseExecutor(JSContext* cx, unsigned argc, Value* vp) { +#ifdef DEBUG CallArgs args = CallArgsFromVp(argc, vp); +#endif // DEBUG MOZ_ASSERT(args.length() == 2); MOZ_ASSERT(args[0].toObject().is()); MOZ_ASSERT(args[1].toObject().is()); diff --git a/js/xpconnect/tests/chrome/test_xrayToJS.xul b/js/xpconnect/tests/chrome/test_xrayToJS.xul index 893f6ab891b0..64c10f201835 100644 --- a/js/xpconnect/tests/chrome/test_xrayToJS.xul +++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul @@ -40,25 +40,37 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 'Uint8ClampedArray']; errorObjectClasses = ['Error', 'InternalError', 'EvalError', 'RangeError', 'ReferenceError', 'SyntaxError', 'TypeError', 'URIError']; + + // A simpleConstructors entry can either be the name of a constructor as a + // string, or an object containing the properties `name`, and `args`. + // In the former case, the constructor is invoked without any args; in the + // latter case, it is invoked with `args` as the arguments list. simpleConstructors = ['Object', 'Function', 'Array', 'Boolean', 'Date', 'Number', - 'String', 'RegExp', 'ArrayBuffer', 'WeakMap', 'Map', 'Set'].concat(typedArrayClasses) - .concat(errorObjectClasses); + 'String', 'RegExp', 'ArrayBuffer', 'WeakMap', 'Map', 'Set', + {name: 'Promise', args: [function(){}]}].concat(typedArrayClasses) + .concat(errorObjectClasses); function go() { window.iwin = document.getElementById('ifr').contentWindow; - // Test constructors that can be instantiated with zero arguments. + // Test constructors that can be instantiated with zero arguments, or with + // a fixed set of arguments provided using `...rest`. for (var c of simpleConstructors) { + var args = []; + if (typeof c === 'object') { + args = c.args; + c = c.name; + } ok(iwin[c], "Constructors appear: " + c); is(iwin[c], Cu.unwaiveXrays(iwin.wrappedJSObject[c]), "we end up with the appropriate constructor: " + c); - is(Cu.unwaiveXrays(Cu.waiveXrays(new iwin[c]).constructor), iwin[c], + is(Cu.unwaiveXrays(Cu.waiveXrays(new iwin[c](...args)).constructor), iwin[c], "constructor property is set up right: " + c); - let expectedProto = /Opaque/.test(new iwin[c]) ? iwin['Object'].prototype + let expectedProto = /Opaque/.test(new iwin[c](...args)) ? iwin['Object'].prototype : iwin[c].prototype; - is(Object.getPrototypeOf(new iwin[c]), expectedProto, + is(Object.getPrototypeOf(new iwin[c](...args)), expectedProto, "prototype is correct: " + c); - is(global(new iwin[c]), iwin, "Got the right global: " + c); + is(global(new iwin[c](...args)), iwin, "Got the right global: " + c); } // Test Object in more detail. @@ -132,6 +144,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 testRegExp(); + testPromise(); + // We could also test DataView and Iterator here for completeness, but it's // more trouble than it's worth. @@ -228,6 +242,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 "$5", "$6", "$7", "$8", "$9", "$_", "$&", "$+", "$`", "$'", Symbol.species]) + gPrototypeProperties['Promise'] = + ["constructor", "catch", "then"]; + gConstructorProperties['Promise'] = + constructorProps(["resolve", "reject", "all", "race", Symbol.species]); + // Sort an array that may contain symbols as well as strings. function sortProperties(arr) { function sortKey(prop) { @@ -846,6 +865,21 @@ for (var prop of props) { } } + // Note: this is a small set of basic tests. More in-depth tests are located + // in test_promise_xrays.html. + function testPromise() { + testXray('Promise', new iwin.Promise(function(){}), new iwin.Promise(function(){})); + + // Test catch and then. + var pr = new iwin.Promise(function(){}); + isnot(pr.catch, Cu.unwaiveXrays(pr.wrappedJSObject.catch), "Different function identities"); + is(Cu.getGlobalForObject(pr.catch), window, "Xray global is correct"); + is(Cu.getGlobalForObject(pr.wrappedJSObject.catch), iwin, "Underlying global is correct"); + + isnot(pr.then, Cu.unwaiveXrays(pr.wrappedJSObject.then), "Different function identities"); + is(Cu.getGlobalForObject(pr.then), window, "Xray global is correct"); + is(Cu.getGlobalForObject(pr.wrappedJSObject.then), iwin, "Underlying global is correct"); + } ]]> diff --git a/toolkit/components/extensions/ExtensionUtils.jsm b/toolkit/components/extensions/ExtensionUtils.jsm index 58886308a719..9ad366b441e9 100644 --- a/toolkit/components/extensions/ExtensionUtils.jsm +++ b/toolkit/components/extensions/ExtensionUtils.jsm @@ -334,10 +334,8 @@ class BaseContext { * belonging to the target scope. Otherwise, undefined. */ wrapPromise(promise, callback = null) { - // Note: `promise instanceof this.cloneScope.Promise` returns true - // here even for promises that do not belong to the content scope. let runSafe = this.runSafe.bind(this); - if (promise.constructor === this.cloneScope.Promise) { + if (promise instanceof this.cloneScope.Promise) { runSafe = this.runSafeWithoutClone.bind(this); }