Backed out changeset a80fdfc128b0 (bug 911216) for high crash-rate on developers - RyanVM request
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 18 Jul 2016 16:14:59 +0200
changeset 330299 fe6985c6e61601b6906304015de6695d25db9e4d
parent 330298 0fbdcd21fad76a00328e67875c6f40dc219235f4
child 330364 279f4307531af445827f59f6706f2c245403dcae
push id9858
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 14:37:10 +0000
treeherdermozilla-aurora@203106ef6cb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs911216
milestone50.0a1
backs outa80fdfc128b0c29dc34dd3fc28868252111a5d52
Backed out changeset a80fdfc128b0 (bug 911216) for high crash-rate on developers - RyanVM request
devtools/server/actors/script.js
devtools/shared/worker/loader.js
docshell/test/browser/browser_timelineMarkers-frame-04.js
docshell/test/browser/browser_timelineMarkers-frame-05.js
dom/bindings/test/test_promise_rejections_from_jsimplemented.html
dom/tests/mochitest/general/test_interfaces.html
dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
dom/workers/test/test_worker_interfaces.js
js/moz.configure
js/src/jit-test/lib/debuggerNXHelper.js
js/src/jit-test/tests/debug/Debugger-onNewPromise-01.js
js/src/jit-test/tests/debug/Debugger-onNewPromise-02.js
js/src/jit-test/tests/debug/Debugger-onNewPromise-03.js
js/src/jit-test/tests/debug/Debugger-onNewPromise-04.js
js/src/jit-test/tests/debug/Debugger-onNewPromise-05.js
js/src/jit-test/tests/debug/Debugger-onNewPromise-06.js
js/src/jit-test/tests/debug/Debugger-onNewPromise-07.js
js/src/jit-test/tests/debug/Debugger-onPromiseSettled-01.js
js/src/jit-test/tests/debug/Debugger-onPromiseSettled-02.js
js/src/jit-test/tests/debug/Debugger-onPromiseSettled-03.js
js/src/jit-test/tests/debug/Debugger-onPromiseSettled-04.js
js/src/jit-test/tests/debug/Debugger-onPromiseSettled-05.js
js/src/jit-test/tests/debug/Debugger-onPromiseSettled-06.js
js/src/jit-test/tests/debug/Memory-drainAllocationsLog-15.js
js/src/jit-test/tests/debug/bug-1102549.js
js/src/jsapi-tests/testPromise.cpp
js/xpconnect/tests/chrome/test_xrayToJS.xul
toolkit/components/extensions/ExtensionUtils.jsm
--- a/devtools/server/actors/script.js
+++ b/devtools/server/actors/script.js
@@ -14,16 +14,17 @@ const { EnvironmentActor } = require("de
 const { FrameActor } = require("devtools/server/actors/frame");
 const { ObjectActor, createValueGrip, longStringGrip } = require("devtools/server/actors/object");
 const { SourceActor, getSourceURL } = require("devtools/server/actors/source");
 const { DebuggerServer } = require("devtools/server/main");
 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");
 const object = require("sdk/util/object");
 const { threadSpec } = require("devtools/shared/specs/script");
 
 const { defer, resolve, reject, all } = promise;
 
--- a/devtools/shared/worker/loader.js
+++ b/devtools/shared/worker/loader.js
@@ -312,16 +312,22 @@ function WorkerDebuggerLoader(options) {
 }
 
 this.WorkerDebuggerLoader = WorkerDebuggerLoader;
 
 // The following APIs rely on the use of Components, and the worker debugger
 // 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,
   ChromeWorker: undefined,
   Cm: undefined,
   Ci: undefined,
   Cu: undefined,
   Cr: undefined,
@@ -485,16 +491,17 @@ this.worker = new WorkerDebuggerLoader({
     "reportError": reportError,
     "rpc": rpc,
     "setImmediate": setImmediate,
     "URL": URL,
   },
   loadSubScript: loadSubScript,
   modules: {
     "Debugger": Debugger,
+    "PromiseDebugging": PromiseDebugging,
     "Services": Object.create(null),
     "chrome": chrome,
     "xpcInspector": xpcInspector
   },
   paths: {
     // ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
     "": "resource://gre/modules/commonjs/",
     // ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
--- a/docshell/test/browser/browser_timelineMarkers-frame-04.js
+++ b/docshell/test/browser/browser_timelineMarkers-frame-04.js
@@ -45,21 +45,17 @@ if (Services.prefs.getBoolPref("javascri
       markers = markers.filter(m => (m.name == "Javascript" &&
                                      m.causeName == "promise callback"));
       ok(markers.length > 0, "Found a Javascript marker");
 
       let frame = markers[0].stack;
       ok(frame.asyncParent !== null, "Parent frame has async parent");
       is(frame.asyncParent.asyncCause, "promise callback",
          "Async parent has correct cause");
-      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",
+      is(frame.asyncParent.functionDisplayName, "do_promise",
          "Async parent has correct function name");
     }
   }, {
     desc: "Async stack trace on Javascript marker with script",
     searchFor: (markers) => {
       return markers.some(m => (m.name == "Javascript" &&
                                 m.causeName == "promise callback"));
     },
@@ -70,19 +66,15 @@ if (Services.prefs.getBoolPref("javascri
       markers = markers.filter(m => (m.name == "Javascript" &&
                                      m.causeName == "promise callback"));
       ok(markers.length > 0, "Found a Javascript marker");
 
       let frame = markers[0].stack;
       ok(frame.asyncParent !== null, "Parent frame has async parent");
       is(frame.asyncParent.asyncCause, "promise callback",
          "Async parent has correct cause");
-      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",
+      is(frame.asyncParent.functionDisplayName, "do_promise_script",
          "Async parent has correct function name");
     }
   });
 }
 
 timelineContentTest(TESTS);
--- a/docshell/test/browser/browser_timelineMarkers-frame-05.js
+++ b/docshell/test/browser/browser_timelineMarkers-frame-05.js
@@ -86,32 +86,20 @@ if (Services.prefs.getBoolPref("javascri
     searchFor: "ConsoleTime",
     setup: function(docShell) {
       let resolver = makePromise();
       resolvePromise(resolver);
     },
     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.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",
+      ok(frame.parent.asyncParent !== null, "Parent frame has async parent");
+      is(frame.parent.asyncParent.asyncCause, "promise callback",
          "Async parent has correct cause");
-      // Skip over self-hosted parts of our Promise implementation.
-      while (asyncFrame.source === 'self-hosted') {
-        asyncFrame = asyncFrame.parent;
-      }
-      is(asyncFrame.functionDisplayName, "makePromise",
+      is(frame.parent.asyncParent.functionDisplayName, "makePromise",
          "Async parent has correct function name");
     }
   });
 }
 
 timelineContentTest(TESTS);
--- a/dom/bindings/test/test_promise_rejections_from_jsimplemented.html
+++ b/dom/bindings/test/test_promise_rejections_from_jsimplemented.html
@@ -20,114 +20,105 @@ https://bugzilla.mozilla.org/show_bug.cg
     is(exn.name, name,
        "Should have the right exception name in test " + testNumber);
     is("filename" in exn ? exn.filename : exn.fileName, filename,
        "Should have the right file name in test " + testNumber);
     is(exn.message, message,
        "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, "InternalError",
+      is(exn.name, "NS_ERROR_UNEXPECTED",
          "Should have one of our synthetic exceptions in test " + testNumber);
     }
     is(exn.stack, stack, "Should have the right stack in test " + testNumber);
   }
 
   function ensurePromiseFail(testNumber, value) {
     ok(false, "Test " + testNumber + " should not have a fulfilled promise");
   }
 
   function doTest() {
     var t = new TestInterfaceJS();
     /* Async parent frames from pushPrefEnv don't show up in e10s.  */
     var isE10S = !SpecialPowers.isMainProcess();
     var asyncStack = SpecialPowers.getBoolPref("javascript.options.asyncstack");
     var ourFile = location.href;
-    var unwrapError = "Promise rejection value is a non-unwrappable cross-compartment wrapper.";
-    var parentFrame = (asyncStack && !isE10S) ? `Async*@${ourFile}:130:3
+    var parentFrame = (asyncStack && !isE10S) ? `Async*@${ourFile}:121:3
 ` : "";
 
     Promise.all([
       t.testPromiseWithThrowingChromePromiseInit().then(
           ensurePromiseFail.bind(null, 1),
-          checkExn.bind(null, 49, "InternalError", unwrapError,
-                        undefined, ourFile, 1,
-                        `doTest@${ourFile}:49:7
+          checkExn.bind(null, 48, "NS_ERROR_UNEXPECTED", "", undefined,
+                        ourFile, 1,
+                        `doTest@${ourFile}:48:7
 ` +
                         parentFrame)),
       t.testPromiseWithThrowingContentPromiseInit(function() {
           thereIsNoSuchContentFunction1();
         }).then(
           ensurePromiseFail.bind(null, 2),
-          checkExn.bind(null, 57, "ReferenceError",
+          checkExn.bind(null, 56, "ReferenceError",
                         "thereIsNoSuchContentFunction1 is not defined",
                         undefined, ourFile, 2,
-                        `doTest/<@${ourFile}:57:11
-doTest@${ourFile}:56:7
+                        `doTest/<@${ourFile}:56:11
+doTest@${ourFile}:55:7
 ` +
                         parentFrame)),
       t.testPromiseWithThrowingChromeThenFunction().then(
           ensurePromiseFail.bind(null, 3),
-          checkExn.bind(null, 0, "InternalError", unwrapError, undefined, "", 3, asyncStack ? (`Async*doTest@${ourFile}:67:7
-` +
-                        parentFrame) : "")),
+          checkExn.bind(null, 0, "NS_ERROR_UNEXPECTED", "", undefined, "", 3, "")),
       t.testPromiseWithThrowingContentThenFunction(function() {
           thereIsNoSuchContentFunction2();
         }).then(
           ensurePromiseFail.bind(null, 4),
-          checkExn.bind(null, 73, "ReferenceError",
+          checkExn.bind(null, 70, "ReferenceError",
                         "thereIsNoSuchContentFunction2 is not defined",
                         undefined, ourFile, 4,
-                        `doTest/<@${ourFile}:73:11
+                        `doTest/<@${ourFile}:70:11
 ` +
-                        (asyncStack ? `Async*doTest@${ourFile}:72:7
+                        (asyncStack ? `Async*doTest@${ourFile}:69:7
 ` : "") +
                         parentFrame)),
       t.testPromiseWithThrowingChromeThenable().then(
           ensurePromiseFail.bind(null, 5),
-          checkExn.bind(null, 0, "InternalError", unwrapError, undefined, "", 5, asyncStack ? (`Async*doTest@${ourFile}:84:7
-` +
-                        parentFrame) : "")),
+          checkExn.bind(null, 0, "NS_ERROR_UNEXPECTED", "", undefined, "", 5, "")),
       t.testPromiseWithThrowingContentThenable({
             then: function() { thereIsNoSuchContentFunction3(); }
         }).then(
           ensurePromiseFail.bind(null, 6),
-          checkExn.bind(null, 90, "ReferenceError",
+          checkExn.bind(null, 85, "ReferenceError",
                         "thereIsNoSuchContentFunction3 is not defined",
                         undefined, ourFile, 6,
-                        `doTest/<.then@${ourFile}:90:32
-` + (asyncStack ? `Async*doTest@${ourFile}:89:7\n` + parentFrame : ""))),
+                        `doTest/<.then@${ourFile}:85:32
+`)),
       t.testPromiseWithDOMExceptionThrowingPromiseInit().then(
           ensurePromiseFail.bind(null, 7),
-          checkExn.bind(null, 98, "NotFoundError",
+          checkExn.bind(null, 93, "NotFoundError",
                         "We are a second DOMException",
                         DOMException.NOT_FOUND_ERR, ourFile, 7,
-                        `doTest@${ourFile}:98:7
+                        `doTest@${ourFile}:93:7
 ` +
                         parentFrame)),
       t.testPromiseWithDOMExceptionThrowingThenFunction().then(
           ensurePromiseFail.bind(null, 8),
-          checkExn.bind(null, asyncStack ? 106 : 0, "NetworkError",
+          checkExn.bind(null, asyncStack ? 101 : 0, "NetworkError",
                          "We are a third DOMException",
                         DOMException.NETWORK_ERR, asyncStack ? ourFile : "", 8,
-                        (asyncStack ? `Async*doTest@${ourFile}:106:7
+                        (asyncStack ? `Async*doTest@${ourFile}:101:7
 ` +
                          parentFrame : ""))),
       t.testPromiseWithDOMExceptionThrowingThenable().then(
           ensurePromiseFail.bind(null, 9),
-          checkExn.bind(null, asyncStack ? 114 : 0, "TypeMismatchError",
+          checkExn.bind(null, 0, "TypeMismatchError",
                         "We are a fourth DOMException",
-                        DOMException.TYPE_MISMATCH_ERR,
-                        asyncStack ? ourFile : "", 9,
-                        (asyncStack ? `Async*doTest@${ourFile}:114:7
-` +
-                         parentFrame : ""))),
+                         DOMException.TYPE_MISMATCH_ERR, "", 9, "")),
     ]).then(SimpleTest.finish,
-            function(err) {
-              ok(false, "One of our catch statements totally failed with err" + err + ', stack: ' + (err ? err.stack : ''));
+            function() {
+              ok(false, "One of our catch statements totally failed");
               SimpleTest.finish();
             });
   }
 
   SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]},
                             doTest);
   </script>
 </head>
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -67,17 +67,16 @@ var ecmaGlobals =
     {name: "Intl", android: false},
     "Iterator",
     "JSON",
     "Map",
     "Math",
     {name: "NaN", xbl: false},
     "Number",
     "Object",
-    "Promise",
     "Proxy",
     "RangeError",
     "ReferenceError",
     "Reflect",
     "RegExp",
     "Set",
     {name: "SharedArrayBuffer", nightly: true},
     {name: "SIMD", nightly: true},
@@ -958,16 +957,18 @@ var interfaceNamesInGlobalScope =
     {name: "PresentationSession", disabled: true, permission: ["presentation"]},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "PresentationSessionConnectEvent", disabled: true, permission: ["presentation"]},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "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!
     {name: "PushSubscription", b2g: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "PushSubscriptionOptions", b2g: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "RadioNodeList",
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
+++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
@@ -42,17 +42,16 @@ var ecmaGlobals =
     {name: "Intl", android: false},
     "Iterator",
     "JSON",
     "Map",
     "Math",
     "NaN",
     "Number",
     "Object",
-    "Promise",
     "Proxy",
     "RangeError",
     "ReferenceError",
     "Reflect",
     "RegExp",
     "Set",
     {name: "SharedArrayBuffer", nightly: true},
     {name: "SIMD", nightly: true},
@@ -171,16 +170,18 @@ var interfaceNamesInGlobalScope =
     "PerformanceMark",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "PerformanceMeasure",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     { 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!
     { name: "PushManager", b2g: false },
 // IMPORTANT: Do not change this list without review from a DOM peer!
     { name: "PushMessageData", b2g: false },
 // IMPORTANT: Do not change this list without review from a DOM peer!
     { name: "PushSubscription", b2g: false },
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/workers/test/test_worker_interfaces.js
+++ b/dom/workers/test/test_worker_interfaces.js
@@ -42,17 +42,16 @@ var ecmaGlobals =
     {name: "Intl", android: false},
     "Iterator",
     "JSON",
     "Map",
     "Math",
     "NaN",
     "Number",
     "Object",
-    "Promise",
     "Proxy",
     "RangeError",
     "ReferenceError",
     "Reflect",
     "RegExp",
     "Set",
     {name: "SharedArrayBuffer", nightly: true},
     {name: "SIMD", nightly: true},
@@ -163,16 +162,18 @@ var interfaceNamesInGlobalScope =
     "PerformanceMark",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "PerformanceMeasure",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     { 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!
     { name: "PushSubscription", b2g: false },
 // IMPORTANT: Do not change this list without review from a DOM peer!
     { name: "PushSubscriptionOptions", b2g: false },
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Request",
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/js/moz.configure
+++ b/js/moz.configure
@@ -34,18 +34,17 @@ def js_disable_shell(value):
     if not value:
         return True
 
 set_config('JS_DISABLE_SHELL', js_disable_shell)
 
 
 # Use SpiderMonkey Promise implementation if it's enabled
 # =======================================================
-js_option('--enable-sm-promise', default=True,
-          help='Enable SpiderMonkey promises')
+js_option('--enable-sm-promise', help='Enable SpiderMonkey promises')
 
 @depends('--enable-sm-promise')
 def sm_promise(value):
     if value:
         return True
 
 set_config('SPIDERMONKEY_PROMISE', sm_promise)
 set_define('SPIDERMONKEY_PROMISE', sm_promise)
--- a/js/src/jit-test/lib/debuggerNXHelper.js
+++ b/js/src/jit-test/lib/debuggerNXHelper.js
@@ -27,26 +27,24 @@ function testDebuggerHooksNX(dbg, g, tes
                    () => { g.eval("42"); });
 
   testDebuggerHook("onEnterFrame",
                    () => { g.eval("(() => {})()"); });
 
   testDebuggerHook("onNewGlobalObject",
                    () => { newGlobal(); });
 
-  if ('Promise' in g) {
-      testDebuggerHook("onNewPromise",
-                       () => { new g.Promise(()=>{}); });
+  testDebuggerHook("onNewPromise",
+                   () => { g.makeFakePromise(); });
 
-      testDebuggerHook("onPromiseSettled",
-                       () => {
-                         var p = new g.Promise(()=>{});
-                         g.settlePromiseNow(p);
-                       });
-  }
+  testDebuggerHook("onPromiseSettled",
+                   () => {
+                     var p = g.makeFakePromise();
+                     g.settleFakePromise(p);
+                   });
 
   // Hooks on frames.
   var onStepHit = false;
   var onPopHit = false;
   dbg.onEnterFrame = (frame) => {
     dbg.onEnterFrame = undefined;
 
     frame.onStep = () => {
--- a/js/src/jit-test/tests/debug/Debugger-onNewPromise-01.js
+++ b/js/src/jit-test/tests/debug/Debugger-onNewPromise-01.js
@@ -1,19 +1,17 @@
 // 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();
 var gw = dbg.addDebuggee(g);
 
 
 let promisesFound = [];
 dbg.onNewPromise = p => { promisesFound.push(p); };
 
-let p1 = new g.Promise(function (){});
+let p1 = g.makeFakePromise()
 dbg.enabled = false;
-let p2 = new g.Promise(function (){});
+let p2 = g.makeFakePromise();
 
 assertEq(promisesFound.indexOf(gw.makeDebuggeeValue(p1)) != -1, true);
 assertEq(promisesFound.indexOf(gw.makeDebuggeeValue(p2)) == -1, true);
--- a/js/src/jit-test/tests/debug/Debugger-onNewPromise-02.js
+++ b/js/src/jit-test/tests/debug/Debugger-onNewPromise-02.js
@@ -1,26 +1,24 @@
 // onNewPromise handlers fire, until they are removed.
-if (!('Promise' in this))
-    quit(0);
 
 var g = newGlobal();
 var dbg = new Debugger(g);
 var log;
 
 log = '';
-new g.Promise(function (){});
+g.makeFakePromise();
 assertEq(log, '');
 
 dbg.onNewPromise = function (promise) {
   log += 'n';
   assertEq(promise.seen, undefined);
   promise.seen = true;
 };
 
 log = '';
-new g.Promise(function (){});
+g.makeFakePromise();
 assertEq(log, 'n');
 
 log = '';
 dbg.onNewPromise = undefined;
-new g.Promise(function (){});
+g.makeFakePromise();
 assertEq(log, '');
--- a/js/src/jit-test/tests/debug/Debugger-onNewPromise-03.js
+++ b/js/src/jit-test/tests/debug/Debugger-onNewPromise-03.js
@@ -1,11 +1,9 @@
 // onNewPromise handlers on different Debugger instances are independent.
-if (!('Promise' in this))
-    quit(0);
 
 var g = newGlobal();
 var dbg1 = new Debugger(g);
 var log1;
 function h1(promise) {
   log1 += 'n';
   assertEq(promise.seen, undefined);
   promise.seen = true;
@@ -15,29 +13,29 @@ var dbg2 = new Debugger(g);
 var log2;
 function h2(promise) {
   log2 += 'n';
   assertEq(promise.seen, undefined);
   promise.seen = true;
 }
 
 log1 = log2 = '';
-new g.Promise(function (){});
+g.makeFakePromise();
 assertEq(log1, '');
 assertEq(log2, '');
 
 log1 = log2 = '';
 dbg1.onNewPromise = h1;
-new g.Promise(function (){});
+g.makeFakePromise();
 assertEq(log1, 'n');
 assertEq(log2, '');
 
 log1 = log2 = '';
 dbg2.onNewPromise = h2;
-new g.Promise(function (){});
+g.makeFakePromise();
 assertEq(log1, 'n');
 assertEq(log2, 'n');
 
 log1 = log2 = '';
 dbg1.onNewPromise = undefined;
-new g.Promise(function (){});
+g.makeFakePromise();
 assertEq(log1, '');
 assertEq(log2, 'n');
--- a/js/src/jit-test/tests/debug/Debugger-onNewPromise-04.js
+++ b/js/src/jit-test/tests/debug/Debugger-onNewPromise-04.js
@@ -1,17 +1,15 @@
 // An onNewPromise handler can disable itself.
-if (!('Promise' in this))
-    quit(0);
 
 var g = newGlobal();
 var dbg = new Debugger(g);
 var log;
 
 dbg.onNewPromise = function (promise) {
   log += 'n';
   dbg.onNewPromise = undefined;
 };
 
 log = '';
-new g.Promise(function (){});
-new g.Promise(function (){});
+g.makeFakePromise();
+g.makeFakePromise();
 assertEq(log, 'n');
--- a/js/src/jit-test/tests/debug/Debugger-onNewPromise-05.js
+++ b/js/src/jit-test/tests/debug/Debugger-onNewPromise-05.js
@@ -1,27 +1,24 @@
 // 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();
-var gw = dbg.addDebuggee(g);
+var dbg = new Debugger(g);
 var log;
 var depth;
 
 dbg.onNewPromise = function (promise) {
   log += '('; depth++;
 
   assertEq(promise.seen, undefined);
   promise.seen = true;
 
   if (depth < 3)
-      gw.executeInGlobal(`new Promise(_=>{})`);
+    g.makeFakePromise();
 
   log += ')'; depth--;
 };
 
 log = '';
 depth = 0;
-new g.Promise(function (){});
+g.makeFakePromise();
 assertEq(log, '((()))');
--- a/js/src/jit-test/tests/debug/Debugger-onNewPromise-06.js
+++ b/js/src/jit-test/tests/debug/Debugger-onNewPromise-06.js
@@ -1,37 +1,35 @@
 // Resumption values from onNewPromise handlers are disallowed.
-if (!('Promise' in this))
-    quit(0);
 
 load(libdir + 'asserts.js');
 
 var g = newGlobal();
 var dbg = new Debugger(g);
 var log;
 
 dbg.onNewPromise = function (g) { log += 'n'; return undefined; };
 log = '';
-assertEq(typeof new g.Promise(function (){}), "object");
+assertEq(typeof g.makeFakePromise(), "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 new g.Promise(function (){}), "object");
+assertEq(typeof g.makeFakePromise(), "object");
 assertEq(log, 'nu');
 
 dbg.onNewPromise = function (g) { log += 'n'; return { throw: "snoo" }; };
 log = '';
-assertEq(typeof new g.Promise(function (){}), "object");
+assertEq(typeof g.makeFakePromise(), "object");
 assertEq(log, 'nu');
 
 dbg.onNewPromise = function (g) { log += 'n'; return null; };
 log = '';
-assertEq(typeof new g.Promise(function (){}), "object");
+assertEq(typeof g.makeFakePromise(), "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 new g.Promise(function (){}), "object");
+assertEq(typeof g.makeFakePromise(), "object");
 assertEq(log, 'nu');
 
--- a/js/src/jit-test/tests/debug/Debugger-onNewPromise-07.js
+++ b/js/src/jit-test/tests/debug/Debugger-onNewPromise-07.js
@@ -1,15 +1,13 @@
 // 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);
 
 let e;
 dbg.uncaughtExceptionHook = ee => { e = ee; };
 dbg.onNewPromise = () => { throw new Error("woops!"); };
 
-assertEq(typeof new g.Promise(function (){}), "object");
+assertEq(typeof g.makeFakePromise(), "object");
 assertEq(!!e, true);
 assertEq(!!e.message.match(/woops/), true);
--- a/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-01.js
+++ b/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-01.js
@@ -1,27 +1,25 @@
 // Test that the onPromiseSettled hook gets called when a promise settles.
-if (!('Promise' in this))
-    quit(0);
 
 var g = newGlobal();
 var dbg = new Debugger();
 var gw = dbg.addDebuggee(g);
 
 let log = "";
 let pw;
 dbg.onPromiseSettled = pw_ => {
   pw = pw_;
   log += "s";
 };
 
-let p = new g.Promise(function (){});
-g.settlePromiseNow(p);
+let p = g.makeFakePromise();
+g.settleFakePromise(p);
 
 assertEq(log, "s");
 assertEq(pw, gw.makeDebuggeeValue(p));
 
 log = "";
 dbg.enabled = false;
-p = new g.Promise(function (){});
-g.settlePromiseNow(p);
+p = g.makeFakePromise();
+g.settleFakePromise(p);
 
 assertEq(log, "");
--- a/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-02.js
+++ b/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-02.js
@@ -1,26 +1,24 @@
 // 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.settlePromiseNow(new g.Promise(function (){}));
+g.settleFakePromise(g.makeFakePromise());
 assertEq(log, '');
 
 dbg.onPromiseSettled = function (promise) {
   log += 's';
   assertEq(promise.seen, undefined);
   promise.seen = true;
 };
 
 log = '';
-g.settlePromiseNow(new g.Promise(function (){}));
+g.settleFakePromise(g.makeFakePromise());
 assertEq(log, 's');
 
 log = '';
 dbg.onPromiseSettled = undefined;
-g.settlePromiseNow(new g.Promise(function (){}));
+g.settleFakePromise(g.makeFakePromise());
 assertEq(log, '');
--- a/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-03.js
+++ b/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-03.js
@@ -1,11 +1,9 @@
 // onPromiseSettled handlers on different Debugger instances are independent.
-if (!('Promise' in this))
-    quit(0);
 
 var g = newGlobal();
 var dbg1 = new Debugger(g);
 var log1;
 function h1(promise) {
   log1 += 's';
   assertEq(promise.seen, undefined);
   promise.seen = true;
@@ -15,29 +13,29 @@ var dbg2 = new Debugger(g);
 var log2;
 function h2(promise) {
   log2 += 's';
   assertEq(promise.seen, undefined);
   promise.seen = true;
 }
 
 log1 = log2 = '';
-g.settlePromiseNow(new g.Promise(function (){}));
+g.settleFakePromise(g.makeFakePromise());
 assertEq(log1, '');
 assertEq(log2, '');
 
 log1 = log2 = '';
 dbg1.onPromiseSettled = h1;
-g.settlePromiseNow(new g.Promise(function (){}));
+g.settleFakePromise(g.makeFakePromise());
 assertEq(log1, 's');
 assertEq(log2, '');
 
 log1 = log2 = '';
 dbg2.onPromiseSettled = h2;
-g.settlePromiseNow(new g.Promise(function (){}));
+g.settleFakePromise(g.makeFakePromise());
 assertEq(log1, 's');
 assertEq(log2, 's');
 
 log1 = log2 = '';
 dbg1.onPromiseSettled = undefined;
-g.settlePromiseNow(new g.Promise(function (){}));
+g.settleFakePromise(g.makeFakePromise());
 assertEq(log1, '');
 assertEq(log2, 's');
--- a/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-04.js
+++ b/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-04.js
@@ -1,17 +1,15 @@
 // An onPromiseSettled handler can disable itself.
-if (!('Promise' in this))
-    quit(0);
 
 var g = newGlobal();
 var dbg = new Debugger(g);
 var log;
 
 dbg.onPromiseSettled = function (promise) {
   log += 's';
   dbg.onPromiseSettled = undefined;
 };
 
 log = '';
-g.settlePromiseNow(new g.Promise(function (){}));
-g.settlePromiseNow(new g.Promise(function (){}));
+g.settleFakePromise(g.makeFakePromise());
+g.settleFakePromise(g.makeFakePromise());
 assertEq(log, 's');
--- a/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-05.js
+++ b/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-05.js
@@ -1,27 +1,24 @@
 // 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();
-var gw = dbg.addDebuggee(g);
+var dbg = new Debugger(g);
 var log;
 var depth;
 
 dbg.onPromiseSettled = function (promise) {
   log += '('; depth++;
 
   assertEq(promise.seen, undefined);
   promise.seen = true;
 
-  if (depth < 3) {
-    gw.executeInGlobal(`settlePromiseNow(new Promise(_=>{}));`);
-  }
+  if (depth < 3)
+    g.settleFakePromise(g.makeFakePromise());
+
   log += ')'; depth--;
 };
 
 log = '';
 depth = 0;
-g.settlePromiseNow(new g.Promise(_=>{}));
+g.settleFakePromise(g.makeFakePromise());
 assertEq(log, '((()))');
--- a/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-06.js
+++ b/js/src/jit-test/tests/debug/Debugger-onPromiseSettled-06.js
@@ -1,37 +1,35 @@
 // Resumption values from onPromiseSettled handlers are disallowed.
-if (!('Promise' in this))
-    quit(0);
 
 load(libdir + 'asserts.js');
 
 var g = newGlobal();
 var dbg = new Debugger(g);
 var log;
 
 dbg.onPromiseSettled = function (g) { log += 's'; return undefined; };
 log = '';
-g.settlePromiseNow(new g.Promise(function (){}));
+g.settleFakePromise(g.makeFakePromise());
 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.settlePromiseNow(new g.Promise(function (){}));
+g.settleFakePromise(g.makeFakePromise());
 assertEq(log, 'su');
 
 dbg.onPromiseSettled = function (g) { log += 's'; return { throw: "snoo" }; };
 log = '';
-g.settlePromiseNow(new g.Promise(function (){}));
+g.settleFakePromise(g.makeFakePromise());
 assertEq(log, 'su');
 
 dbg.onPromiseSettled = function (g) { log += 's'; return null; };
 log = '';
-g.settlePromiseNow(new g.Promise(function (){}));
+g.settleFakePromise(g.makeFakePromise());
 assertEq(log, 'su');
 
 dbg.uncaughtExceptionHook = function (ex) { assertEq(/foopy/.test(ex), true); log += 'u'; }
 dbg.onPromiseSettled = function (g) { log += 's'; throw "foopy"; };
 log = '';
-g.settlePromiseNow(new g.Promise(function (){}));
+g.settleFakePromise(g.makeFakePromise());
 assertEq(log, 'su');
 
--- a/js/src/jit-test/tests/debug/Memory-drainAllocationsLog-15.js
+++ b/js/src/jit-test/tests/debug/Memory-drainAllocationsLog-15.js
@@ -1,25 +1,23 @@
 // Test drainAllocationsLog() and [[Class]] names.
-if (!('Promise' in this))
-    quit(0);
 
 const root = newGlobal();
 const dbg = new Debugger();
 const wrappedRoot = dbg.addDebuggee(root)
 
 root.eval(
   `
   this.tests = [
     { expected: "Object",    test: () => new Object    },
     { expected: "Array",     test: () => []            },
     { expected: "Date",      test: () => new Date      },
     { expected: "RegExp",    test: () => /problems/    },
     { expected: "Int8Array", test: () => new Int8Array },
-    { expected: "Promise",   test: () => new Promise(function (){})},
+    { expected: "Promise",   test: makeFakePromise     },
   ];
   `
 );
 
 
 for (let { expected, test } of root.tests) {
   print(expected);
 
--- a/js/src/jit-test/tests/debug/bug-1102549.js
+++ b/js/src/jit-test/tests/debug/bug-1102549.js
@@ -1,9 +1,5 @@
 // |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.settlePromiseNow(new g.Promise(function (){}));
+g.settleFakePromise(g.makeFakePromise());
--- a/js/src/jsapi-tests/testPromise.cpp
+++ b/js/src/jsapi-tests/testPromise.cpp
@@ -11,19 +11,17 @@
 
 using namespace JS;
 
 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<JSFunction>());
     MOZ_ASSERT(args[1].toObject().is<JSFunction>());
 
     executor_called = true;
     return true;
 }
 
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul
+++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul
@@ -35,47 +35,35 @@ https://bugzilla.mozilla.org/show_bug.cg
     }
   }
 
   typedArrayClasses = ['Uint8Array', 'Int8Array', 'Uint16Array', 'Int16Array',
                        'Uint32Array', 'Int32Array', 'Float32Array', 'Float64Array',
                        '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',
-                        {name: 'Promise', args: [function(){}]}].concat(typedArrayClasses)
-                                                                .concat(errorObjectClasses);
+                        'String', 'RegExp', 'ArrayBuffer', 'WeakMap', 'Map', 'Set'].concat(typedArrayClasses)
+                                                                                   .concat(errorObjectClasses);
 
   function go() {
     window.iwin = document.getElementById('ifr').contentWindow;
 
-    // Test constructors that can be instantiated with zero arguments, or with
-    // a fixed set of arguments provided using `...rest`.
+    // Test constructors that can be instantiated with zero arguments.
     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](...args)).constructor), iwin[c],
+      is(Cu.unwaiveXrays(Cu.waiveXrays(new iwin[c]).constructor), iwin[c],
          "constructor property is set up right: " + c);
-      let expectedProto = /Opaque/.test(new iwin[c](...args)) ? iwin['Object'].prototype
+      let expectedProto = /Opaque/.test(new iwin[c]) ? iwin['Object'].prototype
                                                      : iwin[c].prototype;
-      is(Object.getPrototypeOf(new iwin[c](...args)), expectedProto,
+      is(Object.getPrototypeOf(new iwin[c]), expectedProto,
          "prototype is correct: " + c);
-      is(global(new iwin[c](...args)), iwin, "Got the right global: " + c);
+      is(global(new iwin[c]), iwin, "Got the right global: " + c);
     }
 
     // Test Object in more detail.
     var num = new iwin.Object(4);
     is(Cu.waiveXrays(num).valueOf(), 4, "primitive object construction works");
     is(global(num), iwin, "correct global for num");
     var obj = new iwin.Object();
     obj.foo = 2;
@@ -139,18 +127,16 @@ https://bugzilla.mozilla.org/show_bug.cg
     testArray();
 
     testTypedArrays();
 
     testErrorObjects();
 
     testRegExp();
 
-    testPromise();
-
     // We could also test DataView and Iterator here for completeness, but it's
     // more trouble than it's worth.
 
     SimpleTest.finish();
   }
 
   // Maintain a static list of the properties that are available on each standard
   // prototype, so that we make sure to audit any new ones to make sure they're
@@ -237,21 +223,16 @@ https://bugzilla.mozilla.org/show_bug.cg
      "flags", "global", "ignoreCase", "multiline", "source", "sticky", "unicode",
      "lastIndex"];
   gConstructorProperties['RegExp'] =
     constructorProps(["input", "lastMatch", "lastParen",
                       "leftContext", "rightContext", "$1", "$2", "$3", "$4",
                       "$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) {
       return typeof prop + ":" + prop.toString();
     }
     arr.sort((a, b) => sortKey(a) < sortKey(b) ? -1 : +1);
   }
 
@@ -860,28 +841,13 @@ for (var prop of props) {
 for (var prop of props) {
   Object.defineProperty(RegExp.prototype, prop, origDescs[prop]);
 }
 `);
       }
     }
   }
 
-  // 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");
-  }
 
   ]]>
   </script>
   <iframe id="ifr" onload="go();" src="http://example.org/tests/js/xpconnect/tests/mochitest/file_empty.html" />
 </window>
--- a/toolkit/components/extensions/ExtensionUtils.jsm
+++ b/toolkit/components/extensions/ExtensionUtils.jsm
@@ -329,18 +329,20 @@ class BaseContext {
    *     `callback` function or resolving the wrapped promise.
    *
    * @param {function} [callback] The callback function to wrap
    *
    * @returns {Promise|undefined} If callback is null, a promise object
    *     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 instanceof this.cloneScope.Promise) {
+    if (promise.constructor === this.cloneScope.Promise) {
       runSafe = this.runSafeWithoutClone.bind(this);
     }
 
     if (callback) {
       promise.then(
         args => {
           if (this.unloaded) {
             dump(`Promise resolved after context unloaded\n`);