Backed out 5 changesets (bug 911216) for apparently tripling the runtime of SM(p) jobs along with introducing a failure in SM(p)
authorWes Kocher <wkocher@mozilla.com>
Mon, 04 Apr 2016 15:41:17 -0700
changeset 291558 2e4a8e49b5421ca53853e2a614c4ce569d47d908
parent 291557 ae2f8bdfec618098a37f4cab42a58f548e44f76e
child 291559 df94a439a147929e467ac492c1ce44b387c48333
push id74616
push userkwierso@gmail.com
push dateMon, 04 Apr 2016 22:42:24 +0000
treeherdermozilla-inbound@df94a439a147 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs911216
milestone48.0a1
backs outd7023522452523bef218db9a9b565dafd24f1e9f
2f503e373e6f74b9c22b402e6bcac997e06ee80e
2e98f8b36bc68b505c473ef3bcdc0825dc29708b
bd5acdf4a2a1d587a40658303857ca61c0e87abb
58716e5626909a33ba00a3355df79d6ffad60916
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
Backed out 5 changesets (bug 911216) for apparently tripling the runtime of SM(p) jobs along with introducing a failure in SM(p) Backed out changeset d70235224525 (bug 911216) Backed out changeset 2f503e373e6f (bug 911216) Backed out changeset 2e98f8b36bc6 (bug 911216) Backed out changeset bd5acdf4a2a1 (bug 911216) Backed out changeset 58716e562690 (bug 911216) MozReview-Commit-ID: 807ajHOZvQn
dom/promise/PromiseDebugging.cpp
dom/promise/PromiseDebugging.h
dom/webidl/PromiseDebugging.webidl
js/src/builtin/Promise.cpp
js/src/builtin/Promise.h
js/src/builtin/Promise.js
js/src/builtin/SelfHostingDefines.h
js/src/jit-test/tests/debug/inspect-wrapped-promise.js
js/src/jsapi.cpp
js/src/jsapi.h
js/src/shell/js.cpp
js/src/tests/ecma_6/Promise/promise-rejection-tracking.js
js/src/vm/Debugger.cpp
js/src/vm/Runtime.cpp
js/src/vm/Runtime.h
js/src/vm/SelfHosting.cpp
xpcom/base/CycleCollectedJSRuntime.cpp
xpcom/base/CycleCollectedJSRuntime.h
--- a/dom/promise/PromiseDebugging.cpp
+++ b/dom/promise/PromiseDebugging.cpp
@@ -72,113 +72,16 @@ UnwrapPromise(JS::Handle<JSObject*> aPro
 {
   Promise* promise;
   if (NS_WARN_IF(NS_FAILED(UNWRAP_OBJECT(Promise, aPromise, promise)))) {
     aRv.ThrowTypeError<MSG_IS_NOT_PROMISE>(NS_LITERAL_STRING("Argument"));
     return nullptr;
   }
   return promise;
 }
-#endif // SPIDERMONKEY_PROMISE
-
-#ifdef SPIDERMONKEY_PROMISE
-/* static */ void
-PromiseDebugging::GetState(GlobalObject& aGlobal, JS::Handle<JSObject*> aPromise,
-                           PromiseDebuggingStateHolder& aState,
-                           ErrorResult& aRv)
-{
-  JSContext* cx = aGlobal.Context();
-  JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(aPromise));
-  if (!obj || !JS::IsPromiseObject(obj)) {
-    aRv.ThrowTypeError<MSG_IS_NOT_PROMISE>(NS_LITERAL_STRING(
-        "Argument of PromiseDebugging.getState"));
-    return;
-  }
-  switch (JS::GetPromiseState(obj)) {
-  case JS::PromiseState::Pending:
-    aState.mState = PromiseDebuggingState::Pending;
-    break;
-  case JS::PromiseState::Fulfilled:
-    aState.mState = PromiseDebuggingState::Fulfilled;
-    aState.mValue = JS::GetPromiseResult(obj);
-    break;
-  case JS::PromiseState::Rejected:
-    aState.mState = PromiseDebuggingState::Rejected;
-    aState.mReason = JS::GetPromiseResult(obj);
-    break;
-  }
-}
-
-/* static */ void
-PromiseDebugging::GetPromiseID(GlobalObject& aGlobal,
-                               JS::Handle<JSObject*> aPromise,
-                               nsString& aID,
-                               ErrorResult& aRv)
-{
-  JSContext* cx = aGlobal.Context();
-  JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(aPromise));
-  if (!obj || !JS::IsPromiseObject(obj)) {
-    aRv.ThrowTypeError<MSG_IS_NOT_PROMISE>(NS_LITERAL_STRING(
-        "Argument of PromiseDebugging.getState"));
-    return;
-  }
-  uint64_t promiseID = JS::GetPromiseID(obj);
-  aID = sIDPrefix;
-  aID.AppendInt(promiseID);
-}
-
-/* static */ void
-PromiseDebugging::GetAllocationStack(GlobalObject& aGlobal,
-                                     JS::Handle<JSObject*> aPromise,
-                                     JS::MutableHandle<JSObject*> aStack,
-                                     ErrorResult& aRv)
-{
-  JSContext* cx = aGlobal.Context();
-  JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(aPromise));
-  if (!obj || !JS::IsPromiseObject(obj)) {
-    aRv.ThrowTypeError<MSG_IS_NOT_PROMISE>(NS_LITERAL_STRING(
-        "Argument of PromiseDebugging.getAllocationStack"));
-    return;
-  }
-  aStack.set(JS::GetPromiseAllocationSite(obj));
-}
-
-/* static */ void
-PromiseDebugging::GetRejectionStack(GlobalObject& aGlobal,
-                                    JS::Handle<JSObject*> aPromise,
-                                    JS::MutableHandle<JSObject*> aStack,
-                                    ErrorResult& aRv)
-{
-  JSContext* cx = aGlobal.Context();
-  JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(aPromise));
-  if (!obj || !JS::IsPromiseObject(obj)) {
-    aRv.ThrowTypeError<MSG_IS_NOT_PROMISE>(NS_LITERAL_STRING(
-        "Argument of PromiseDebugging.getRejectionStack"));
-    return;
-  }
-  aStack.set(JS::GetPromiseResolutionSite(obj));
-}
-
-/* static */ void
-PromiseDebugging::GetFullfillmentStack(GlobalObject& aGlobal,
-                                       JS::Handle<JSObject*> aPromise,
-                                       JS::MutableHandle<JSObject*> aStack,
-                                       ErrorResult& aRv)
-{
-  JSContext* cx = aGlobal.Context();
-  JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(aPromise));
-  if (!obj || !JS::IsPromiseObject(obj)) {
-    aRv.ThrowTypeError<MSG_IS_NOT_PROMISE>(NS_LITERAL_STRING(
-        "Argument of PromiseDebugging.getFulfillmentStack"));
-    return;
-  }
-  aStack.set(JS::GetPromiseResolutionSite(obj));
-}
-
-#else
 
 /* static */ void
 PromiseDebugging::GetState(GlobalObject&, JS::Handle<JSObject*> aPromise,
                            PromiseDebuggingStateHolder& aState,
                            ErrorResult& aRv)
 {
   Promise* promise = UnwrapPromise(aPromise, aRv);
   if (aRv.Failed()) {
--- a/dom/promise/PromiseDebugging.h
+++ b/dom/promise/PromiseDebugging.h
@@ -27,44 +27,43 @@ class UncaughtRejectionObserver;
 class FlushRejections;
 
 class PromiseDebugging
 {
 public:
   static void Init();
   static void Shutdown();
 
+#ifndef SPIDERMONKEY_PROMISE
   static void GetState(GlobalObject&, JS::Handle<JSObject*> aPromise,
                        PromiseDebuggingStateHolder& aState,
                        ErrorResult& aRv);
 
-  static void GetPromiseID(GlobalObject&, JS::Handle<JSObject*>, nsString&,
-                           ErrorResult&);
-
   static void GetAllocationStack(GlobalObject&, JS::Handle<JSObject*> aPromise,
                                  JS::MutableHandle<JSObject*> aStack,
                                  ErrorResult& aRv);
   static void GetRejectionStack(GlobalObject&, JS::Handle<JSObject*> aPromise,
                                 JS::MutableHandle<JSObject*> aStack,
                                 ErrorResult& aRv);
   static void GetFullfillmentStack(GlobalObject&,
                                    JS::Handle<JSObject*> aPromise,
                                    JS::MutableHandle<JSObject*> aStack,
                                    ErrorResult& aRv);
-
-#ifndef SPIDERMONKEY_PROMISE
   static void GetDependentPromises(GlobalObject&,
                                    JS::Handle<JSObject*> aPromise,
                                    nsTArray<RefPtr<Promise>>& aPromises,
                                    ErrorResult& aRv);
   static double GetPromiseLifetime(GlobalObject&,
                                    JS::Handle<JSObject*> aPromise,
                                    ErrorResult& aRv);
   static double GetTimeToSettle(GlobalObject&, JS::Handle<JSObject*> aPromise,
                                 ErrorResult& aRv);
+
+  static void GetPromiseID(GlobalObject&, JS::Handle<JSObject*>, nsString&,
+                           ErrorResult&);
 #endif // SPIDERMONKEY_PROMISE
 
   // Mechanism for watching uncaught instances of Promise.
   // XXXbz figure out the plan
   static void AddUncaughtRejectionObserver(GlobalObject&,
                                            UncaughtRejectionObserver& aObserver);
   static bool RemoveUncaughtRejectionObserver(GlobalObject&,
                                               UncaughtRejectionObserver& aObserver);
--- a/dom/webidl/PromiseDebugging.webidl
+++ b/dom/webidl/PromiseDebugging.webidl
@@ -47,39 +47,33 @@ callback interface UncaughtRejectionObse
    * @param p A Promise that was previously left in uncaught state is
    * now caught, i.e. it is not the last in its chain anymore.
    */
   void onConsumed(Promise<any> p);
 };
 
 [ChromeOnly, Exposed=(Window,System)]
 interface PromiseDebugging {
+#ifndef SPIDERMONKEY_PROMISE
   /**
    * The various functions on this interface all expect to take promises but
    * don't want the WebIDL behavior of assimilating random passed-in objects
    * into promises.  They also want to treat Promise subclass instances as
    * promises instead of wrapping them in a vanilla Promise, which is what the
    * IDL spec says to do.  So we list all our arguments as "object" instead of
    * "Promise" and check for them being a Promise internally.
    */
 
   /**
    * Get the current state of the given promise.
    */
   [Throws]
   static PromiseDebuggingStateHolder getState(object p);
 
   /**
-   * Return an identifier for a promise. This identifier is guaranteed
-   * to be unique to the current process.
-   */
-  [Throws]
-  static DOMString getPromiseID(object p);
-
-  /**
    * Return the stack to the promise's allocation point.  This can
    * return null if the promise was not created from script.
    */
   [Throws]
   static object? getAllocationStack(object p);
 
   /**
    * Return the stack to the promise's rejection point, if the
@@ -92,17 +86,23 @@ interface PromiseDebugging {
   /**
    * Return the stack to the promise's fulfillment point, if the
    * fulfillment happened from script.  This can return null if the
    * promise has not been fulfilled or was not fulfilled from script.
    */
   [Throws]
   static object? getFullfillmentStack(object p);
 
-#ifndef SPIDERMONKEY_PROMISE
+  /**
+   * Return an identifier for a promise. This identifier is guaranteed
+   * to be unique to this instance of Firefox.
+   */
+  [Throws]
+  static DOMString getPromiseID(object p);
+
   /**
    * Get the promises directly depending on a given promise.  These are:
    *
    * 1) Return values of then() calls on the promise
    * 2) Return values of Promise.all() if the given promise was passed in as one
    *    of the arguments.
    * 3) Return values of Promise.race() if the given promise was passed in as
    *    one of the arguments.
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -9,17 +9,16 @@
 
 #include "mozilla/Atomics.h"
 
 #include "jscntxt.h"
 
 #include "gc/Heap.h"
 #include "js/Date.h"
 #include "js/Debug.h"
-#include "vm/SelfHosting.h"
 
 #include "jsobjinlines.h"
 
 #include "vm/NativeObject-inl.h"
 
 using namespace js;
 
 static const JSFunctionSpec promise_methods[] = {
@@ -36,47 +35,17 @@ static const JSFunctionSpec promise_stat
     JS_FS_END
 };
 
 static const JSPropertySpec promise_static_properties[] = {
     JS_SELF_HOSTED_SYM_GET(species, "Promise_static_get_species", 0),
     JS_PS_END
 };
 
-static Value
-Now()
-{
-    return JS::TimeValue(JS::TimeClip(static_cast<double>(PRMJ_Now()) / PRMJ_USEC_PER_MSEC));
-}
-
-static bool
-CreateResolvingFunctions(JSContext* cx, HandleValue promise,
-                         MutableHandleValue resolveVal,
-                         MutableHandleValue rejectVal)
-{
-    InvokeArgs args(cx);
-    if (!args.init(1))
-        return false;
-    args.setThis(UndefinedValue());
-    args[0].set(promise);
-
-    if (!CallSelfHostedFunction(cx, cx->names().CreateResolvingFunctions, args))
-        return false;
-
-    RootedArrayObject resolvingFunctions(cx, &args.rval().toObject().as<ArrayObject>());
-    resolveVal.set(resolvingFunctions->getDenseElement(0));
-    rejectVal.set(resolvingFunctions->getDenseElement(1));
-
-    MOZ_ASSERT(IsCallable(resolveVal));
-    MOZ_ASSERT(IsCallable(rejectVal));
-
-    return true;
-}
-
-// ES2016, February 12 draft, 25.4.3.1. steps 3-11.
+// ES6, 25.4.3.1. steps 3-11.
 PromiseObject*
 PromiseObject::create(JSContext* cx, HandleObject executor, HandleObject proto /* = nullptr */)
 {
     MOZ_ASSERT(executor->isCallable());
 
     RootedObject usedProto(cx, proto);
     bool wrappedProto = false;
     // If the proto is wrapped, that means the current function is running
@@ -99,60 +68,74 @@ PromiseObject::create(JSContext* cx, Han
         // All state stored in a Promise's fixed slots must be created in the
         // same compartment, so we get all of that out of the way here.
         // (Except for the resolution functions, which are created below.)
         mozilla::Maybe<AutoCompartment> ac;
         if (wrappedProto)
             ac.emplace(cx, usedProto);
 
         promise = &NewObjectWithClassProto(cx, &class_, usedProto)->as<PromiseObject>();
+
+        // Step 4.
         if (!promise)
             return nullptr;
 
-        // Step 4.
+        // Step 5.
         promise->setFixedSlot(PROMISE_STATE_SLOT, Int32Value(PROMISE_STATE_PENDING));
 
-        // Step 5.
+        // Step 6.
         RootedArrayObject reactions(cx, NewDenseEmptyArray(cx));
         if (!reactions)
             return nullptr;
         promise->setFixedSlot(PROMISE_FULFILL_REACTIONS_SLOT, ObjectValue(*reactions));
 
-        // Step 6.
+        // Step 7.
         reactions = NewDenseEmptyArray(cx);
         if (!reactions)
             return nullptr;
         promise->setFixedSlot(PROMISE_REJECT_REACTIONS_SLOT, ObjectValue(*reactions));
 
-        // Step 7.
-        promise->setFixedSlot(PROMISE_IS_HANDLED_SLOT,
-                              Int32Value(PROMISE_IS_HANDLED_STATE_UNHANDLED));
-
-        // Store an allocation stack so we can later figure out what the
-        // control flow was for some unexpected results. Frightfully expensive,
-        // but oh well.
         RootedObject stack(cx);
         if (!JS::CaptureCurrentStack(cx, &stack, 0))
             return nullptr;
-        promise->setFixedSlot(PROMISE_ALLOCATION_SITE_SLOT, ObjectOrNullValue(stack));
-        promise->setFixedSlot(PROMISE_ALLOCATION_TIME_SLOT, Now());
+        promise->setFixedSlot(PROMISE_ALLOCATION_SITE_SLOT, ObjectValue(*stack));
+        Value now = JS::TimeValue(JS::TimeClip(static_cast<double>(PRMJ_Now()) /
+                                               PRMJ_USEC_PER_MSEC));
+        promise->setFixedSlot(PROMISE_ALLOCATION_TIME_SLOT, now);
     }
 
     RootedValue promiseVal(cx, ObjectValue(*promise));
     if (wrappedProto && !cx->compartment()->wrap(cx, &promiseVal))
         return nullptr;
 
     // Step 8.
     // The resolving functions are created in the compartment active when the
     // (maybe wrapped) Promise constructor was called. They contain checks and
     // can unwrap the Promise if required.
-    RootedValue resolveVal(cx);
-    RootedValue rejectVal(cx);
-    if (!CreateResolvingFunctions(cx, promiseVal, &resolveVal, &rejectVal))
+    RootedValue resolvingFunctionsVal(cx);
+    if (!GlobalObject::getIntrinsicValue(cx, cx->global(), cx->names().CreateResolvingFunctions,
+                                         &resolvingFunctionsVal))
+    {
+        return nullptr;
+    }
+    InvokeArgs args(cx);
+    if (!args.init(1))
         return nullptr;
+    args.setCallee(resolvingFunctionsVal);
+    args.setThis(UndefinedValue());
+    args[0].set(promiseVal);
+
+    if (!Invoke(cx, args))
+        return nullptr;
+
+    RootedArrayObject resolvingFunctions(cx, &args.rval().toObject().as<ArrayObject>());
+    RootedValue resolveVal(cx, resolvingFunctions->getDenseElement(0));
+    MOZ_ASSERT(IsCallable(resolveVal));
+    RootedValue rejectVal(cx, resolvingFunctions->getDenseElement(1));
+    MOZ_ASSERT(IsCallable(rejectVal));
 
     // Need to wrap the resolution functions before storing them on the Promise.
     if (wrappedProto) {
         AutoCompartment ac(cx, promise);
         RootedValue wrappedResolveVal(cx, resolveVal);
         RootedValue wrappedRejectVal(cx, rejectVal);
         if (!cx->compartment()->wrap(cx, &wrappedResolveVal) ||
             !cx->compartment()->wrap(cx, &wrappedRejectVal))
@@ -189,37 +172,36 @@ PromiseObject::create(JSContext* cx, Han
         args.setCallee(rejectVal);
         args.setThis(UndefinedValue());
         args[0].set(exceptionVal);
 
         if (!Invoke(cx, args))
             return nullptr;
     }
 
-    // Let the Debugger know about this Promise.
     JS::dbg::onNewPromise(cx, promise);
 
     // Step 11.
     return promise;
 }
 
 namespace {
 // Generator used by PromiseObject::getID.
 mozilla::Atomic<uint64_t> gIDGenerator(0);
 } // namespace
 
-uint64_t
+double
 PromiseObject::getID()
 {
     Value idVal(getReservedSlot(PROMISE_ID_SLOT));
     if (idVal.isUndefined()) {
         idVal.setDouble(++gIDGenerator);
         setReservedSlot(PROMISE_ID_SLOT, idVal);
     }
-    return uint64_t(idVal.toNumber());
+    return idVal.toNumber();
 }
 
 /**
  * Returns all promises that directly depend on this one. That means those
  * created by calling `then` on this promise, or the promise returned by
  * `Promise.all(iterable)` or `Promise.race(iterable)`, with this promise
  * being a member of the passed-in `iterable`.
  *
@@ -402,147 +384,16 @@ PromiseObject::reject(JSContext* cx, Han
     if (!args.init(1))
         return false;
     args.setCallee(funVal);
     args.setThis(UndefinedValue());
     args[0].set(rejectionValue);
     return Invoke(cx, args);
 }
 
-void PromiseObject::onSettled(JSContext* cx)
-{
-    Rooted<PromiseObject*> promise(cx, this);
-    RootedObject stack(cx);
-    if (!JS::CaptureCurrentStack(cx, &stack, 0)) {
-        cx->clearPendingException();
-        return;
-    }
-    promise->setFixedSlot(PROMISE_RESOLUTION_SITE_SLOT, ObjectOrNullValue(stack));
-    promise->setFixedSlot(PROMISE_RESOLUTION_TIME_SLOT, Now());
-
-    if (promise->state() == JS::PromiseState::Rejected &&
-        promise->getFixedSlot(PROMISE_IS_HANDLED_SLOT).toInt32() !=
-            PROMISE_IS_HANDLED_STATE_HANDLED)
-    {
-        cx->runtime()->addUnhandledRejectedPromise(cx, promise);
-    }
-
-    JS::dbg::onPromiseSettled(cx, promise);
-}
-
-// ES6, 25.4.2.1.
-bool
-PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    RootedFunction job(cx, &args.callee().as<JSFunction>());
-    RootedNativeObject jobArgs(cx, &job->getExtendedSlot(0).toObject().as<NativeObject>());
-
-    RootedValue argument(cx, jobArgs->getDenseElement(1));
-
-    // Step 1 (omitted).
-
-    // Steps 2-3.
-    RootedValue handlerVal(cx, jobArgs->getDenseElement(0));
-    RootedValue handlerResult(cx);
-    bool shouldReject = false;
-
-    // Steps 4-7.
-    if (handlerVal.isNumber()) {
-        int32_t handlerNum = int32_t(handlerVal.toNumber());
-        // Step 4.
-        if (handlerNum == PROMISE_HANDLER_IDENTITY) {
-            handlerResult = argument;
-        } else {
-            // Step 5.
-            MOZ_ASSERT(handlerNum == PROMISE_HANDLER_THROWER);
-            shouldReject = true;
-            handlerResult = argument;
-        }
-    } else {
-        // Step 6.
-        InvokeArgs args2(cx);
-        if (!args2.init(1))
-            return false;
-        args2.setThis(UndefinedValue());
-        args2.setCallee(handlerVal);
-        args2[0].set(argument);
-        if (Invoke(cx, args2)) {
-            handlerResult = args2.rval();
-        } else {
-            shouldReject = true;
-            // Not much we can do about uncatchable exceptions, so just bail
-            // for those.
-            if (!cx->isExceptionPending() || !GetAndClearException(cx, &handlerResult))
-                return false;
-        }
-    }
-
-    // Steps 7-9.
-    InvokeArgs args2(cx);
-    if (!args2.init(1))
-        return false;
-    args2.setThis(UndefinedValue());
-    args2[0].set(handlerResult);
-    if (shouldReject) {
-        args2.setCallee(jobArgs->getDenseElement(3));
-    } else {
-        args2.setCallee(jobArgs->getDenseElement(2));
-    }
-    bool result = Invoke(cx, args2);
-
-    args.rval().set(args2.rval());
-    return result;
-}
-
-// ES6, 25.4.2.2.
-bool
-PromiseResolveThenableJob(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    RootedFunction job(cx, &args.callee().as<JSFunction>());
-    RootedNativeObject jobArgs(cx, &job->getExtendedSlot(0).toObject().as<NativeObject>());
-
-    RootedValue promise(cx, jobArgs->getDenseElement(2));
-    RootedValue then(cx, jobArgs->getDenseElement(0));
-    RootedValue thenable(cx, jobArgs->getDenseElement(1));
-
-    // Step 1.
-    RootedValue resolveVal(cx);
-    RootedValue rejectVal(cx);
-    if (!CreateResolvingFunctions(cx, promise, &resolveVal, &rejectVal))
-        return false;
-
-    // Step 2.
-    InvokeArgs args2(cx);
-    if (!args2.init(2))
-        return false;
-    args2.setThis(thenable);
-    args2.setCallee(then);
-    args2[0].set(resolveVal);
-    args2[1].set(rejectVal);
-
-    // In difference to the usual pattern, we return immediately on success.
-    if (Invoke(cx, args2))
-        return true;
-
-    RootedValue thenCallResult(cx);
-    if (!GetAndClearException(cx, &thenCallResult))
-        return false;
-
-    InvokeArgs rejectArgs(cx);
-    if (!rejectArgs.init(1))
-        return false;
-    rejectArgs.setThis(UndefinedValue());
-    rejectArgs.setCallee(rejectVal);
-    rejectArgs[0].set(thenCallResult);
-
-    return Invoke(cx, rejectArgs);
-}
-
 } // namespace js
 
 static JSObject*
 CreatePromisePrototype(JSContext* cx, JSProtoKey key)
 {
     return cx->global()->createBlankPrototype(cx, &PromiseObject::protoClass_);
 }
 
--- a/js/src/builtin/Promise.h
+++ b/js/src/builtin/Promise.h
@@ -14,17 +14,17 @@
 
 namespace js {
 
 class AutoSetNewObjectMetadata;
 
 class PromiseObject : public NativeObject
 {
   public:
-    static const unsigned RESERVED_SLOTS = 12;
+    static const unsigned RESERVED_SLOTS = 11;
     static const Class class_;
     static const Class protoClass_;
     static PromiseObject* create(JSContext* cx, HandleObject executor,
                                  HandleObject proto = nullptr);
 
     JS::PromiseState state() {
         int32_t state = getFixedSlot(PROMISE_STATE_SLOT).toInt32();
         MOZ_ASSERT(state >= 0 && state <= int32_t(JS::PromiseState::Rejected));
@@ -37,47 +37,27 @@ class PromiseObject : public NativeObjec
     Value reason() {
         MOZ_ASSERT(state() == JS::PromiseState::Rejected);
         return getFixedSlot(PROMISE_RESULT_SLOT);
     }
 
     bool resolve(JSContext* cx, HandleValue resolutionValue);
     bool reject(JSContext* cx, HandleValue rejectionValue);
 
-    void onSettled(JSContext* cx);
-
     double allocationTime() { return getFixedSlot(PROMISE_ALLOCATION_TIME_SLOT).toNumber(); }
     double resolutionTime() { return getFixedSlot(PROMISE_RESOLUTION_TIME_SLOT).toNumber(); }
-    JSObject* allocationSite() {
-        return getFixedSlot(PROMISE_ALLOCATION_SITE_SLOT).toObjectOrNull();
-    }
-    JSObject* resolutionSite() {
-        return getFixedSlot(PROMISE_RESOLUTION_SITE_SLOT).toObjectOrNull();
-    }
+    JSObject* allocationSite() { return &getFixedSlot(PROMISE_ALLOCATION_SITE_SLOT).toObject(); }
+    JSObject* resolutionSite() { return &getFixedSlot(PROMISE_RESOLUTION_SITE_SLOT).toObject(); }
     double lifetime() {
         double now = JS::TimeClip(static_cast<double>(PRMJ_Now()) / PRMJ_USEC_PER_MSEC).toDouble();
         return now - allocationTime();
     }
     double timeToResolution() {
         MOZ_ASSERT(state() != JS::PromiseState::Pending);
         return resolutionTime() - allocationTime();
     }
     bool dependentPromises(JSContext* cx, AutoValueVector& values);
-    uint64_t getID();
-    bool markedAsUncaught() {
-        return getFixedSlot(PROMISE_IS_HANDLED_SLOT).toInt32() != PROMISE_IS_HANDLED_STATE_HANDLED;
-    }
-    void markAsReported() {
-        MOZ_ASSERT(getFixedSlot(PROMISE_IS_HANDLED_SLOT).toInt32() ==
-                   PROMISE_IS_HANDLED_STATE_UNHANDLED);
-        setFixedSlot(PROMISE_IS_HANDLED_SLOT, Int32Value(PROMISE_IS_HANDLED_STATE_REPORTED));
-    }
+    double getID();
 };
 
-// ES6, 25.4.2.1.
-bool PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp);
-
-// ES6, 25.4.2.2.
-bool PromiseResolveThenableJob(JSContext* cx, unsigned argc, Value* vp);
-
 } // namespace js
 
 #endif /* builtin_Promise_h */
--- a/js/src/builtin/Promise.js
+++ b/js/src/builtin/Promise.js
@@ -119,17 +119,16 @@ function CreateResolvingFunctions(promis
 function FulfillPromise(promise, value) {
     return ResolvePromise(promise, value, PROMISE_FULFILL_REACTIONS_SLOT, PROMISE_STATE_FULFILLED);
 }
 function FulfillUnwrappedPromise(value) {
     return ResolvePromise(this, value, PROMISE_FULFILL_REACTIONS_SLOT, PROMISE_STATE_FULFILLED);
 }
 
 // Commoned-out implementation of 25.4.1.4. and 25.4.1.7.
-// ES2016 February 12 draft.
 function ResolvePromise(promise, valueOrReason, reactionsSlot, state) {
     // Step 1.
     assert(GetPromiseState(promise) === PROMISE_STATE_PENDING,
            "Can't resolve non-pending promise");
     assert(state >= PROMISE_STATE_PENDING && state <= PROMISE_STATE_REJECTED,
            `Invalid Promise state <${state}>`);
 
     // Step 2.
@@ -147,21 +146,22 @@ function ResolvePromise(promise, valueOr
     // Step 6.
     UnsafeSetReservedSlot(promise, PROMISE_STATE_SLOT, state);
 
     // Also null out the resolve/reject functions so they can be GC'd.
     UnsafeSetReservedSlot(promise, PROMISE_RESOLVE_FUNCTION_SLOT, null);
     UnsafeSetReservedSlot(promise, PROMISE_REJECT_FUNCTION_SLOT, null);
 
     // Now that everything else is done, do the things the debugger needs.
-    // Step 7 of RejectPromise implemented in the debugger intrinsic.
+    let site = _dbg_captureCurrentStack(0);
+    UnsafeSetReservedSlot(promise, PROMISE_RESOLUTION_SITE_SLOT, site);
+    UnsafeSetReservedSlot(promise, PROMISE_RESOLUTION_TIME_SLOT, std_Date_now());
     _dbg_onPromiseSettled(promise);
 
-    // Step 7 of FulfillPromise.
-    // Step 8 of RejectPromise.
+    // Step 7.
     return TriggerPromiseReactions(reactions, valueOrReason);
 }
 
 // Used to verify that an object is a PromiseCapability record.
 var PromiseCapabilityRecordProto = {__proto__: null};
 
 // ES6, 25.4.1.5.
 // Creates PromiseCapability records, see 25.4.1.1.
@@ -204,49 +204,89 @@ function NewPromiseCapability(C) {
         promise,
         resolve,
         reject
     };
 }
 
 // ES6, 25.4.1.6. is implemented as an intrinsic in SelfHosting.cpp.
 
-// ES2016, February 12 draft, 25.4.1.7.
+// ES6, 25.4.1.7.
 function RejectPromise(promise, reason) {
     return ResolvePromise(promise, reason, PROMISE_REJECT_REACTIONS_SLOT, PROMISE_STATE_REJECTED);
 }
 
 // ES6, 25.4.1.8.
 function TriggerPromiseReactions(reactions, argument) {
     // Step 1.
     for (var i = 0, len = reactions.length; i < len; i++)
         EnqueuePromiseReactionJob(reactions[i], argument);
     // Step 2 (implicit).
 }
 
-// ES2016, February 12 draft 25.4.1.9, implemented in SelfHosting.cpp.
-
 // ES6, 25.4.2.1.
 function EnqueuePromiseReactionJob(reaction, argument) {
-    let capabilities = reaction.capabilities;
-    _EnqueuePromiseReactionJob([reaction.handler,
-                                argument,
-                                capabilities.resolve,
-                                capabilities.reject
-                               ],
-                               capabilities.promise);
+    _EnqueuePromiseJob(function PromiseReactionJob() {
+        // Step 1.
+        assert(IsPromiseReaction(reaction), "Invalid promise reaction record");
+
+        // Step 2.
+        let promiseCapability = reaction.capabilities;
+
+        // Step 3.
+        let handler = reaction.handler;
+        let handlerResult = argument;
+        let shouldReject = false;
+
+        // Steps 4-6.
+        if (handler === PROMISE_HANDLER_IDENTITY) {
+            // handlerResult = argument; (implicit)
+        } else if (handler === PROMISE_HANDLER_THROWER) {
+            // handlerResult = argument; (implicit)
+            shouldReject = true;
+        } else {
+            try {
+                handlerResult = callContentFunction(handler, undefined, argument);
+            } catch (e) {
+                handlerResult = e;
+                shouldReject = true;
+            }
+        }
+
+        // Step 7.
+        if (shouldReject) {
+            // Step 7.a.
+            callContentFunction(promiseCapability.reject, undefined, handlerResult);
+
+            // Step 7.b.
+            return;
+        }
+
+        // Steps 8-9.
+        return callContentFunction(promiseCapability.resolve, undefined, handlerResult);
+    });
 }
 
 // ES6, 25.4.2.2.
 function EnqueuePromiseResolveThenableJob(promiseToResolve, thenable, then) {
-    _EnqueuePromiseResolveThenableJob([then,
-                                       thenable,
-                                       promiseToResolve
-                                      ],
-                                      promiseToResolve);
+    _EnqueuePromiseJob(function PromiseResolveThenableJob() {
+        // Step 1.
+        let {0: resolve, 1: reject} = CreateResolvingFunctions(promiseToResolve);
+
+        // Steps 2-3.
+        try {
+            // Step 2.
+            callContentFunction(then, thenable, resolve, reject);
+        } catch (thenCallResult) {
+            // Steps 3.a-b.
+            callFunction(reject, undefined, thenCallResult);
+        }
+
+        // Step 4 (implicit, no need to return anything).
+    });
 }
 
 // ES6, 25.4.3.1. (Implemented in C++).
 
 // ES7 2016-01-21 draft, 25.4.4.1.
 function Promise_static_all(iterable) {
     // Step 1.
     let C = this;
@@ -856,17 +896,17 @@ function UnwrappedPerformPromiseThen(ful
     function onRejected(argument) {
         return UnsafeCallWrappedFunction(rejectedHandler, undefined, argument);
     }
     return PerformPromiseThen(this, IsCallable(fulfilledHandler) ? onFulfilled : fulfilledHandler,
                               IsCallable(rejectedHandler) ? onRejected : rejectedHandler,
                               resultCapability);
 }
 
-// ES2016, March 1, 2016 draft, 25.4.5.3.1.
+// ES6, 25.4.5.3.1.
 function PerformPromiseThen(promise, onFulfilled, onRejected, resultCapability) {
     // Step 1.
     assert(IsPromise(promise), "Can't call PerformPromiseThen on non-Promise objects");
 
     // Step 2.
     assert(IsPromiseCapability(resultCapability), "Invalid promise capability record");
 
     // Step 3.
@@ -910,38 +950,25 @@ function PerformPromiseThen(promise, onF
         // Step 8.a.
         let value = UnsafeGetReservedSlot(promise, PROMISE_RESULT_SLOT);
 
         // Step 8.b.
         EnqueuePromiseReactionJob(fulfillReaction, value);
     }
 
     // Step 9.
-    else {
+    else if (state === PROMISE_STATE_REJECTED) {
         // Step 9.a.
-        assert(state === PROMISE_STATE_REJECTED, "Invalid Promise state " + state);
-
-        // Step 9.b.
         let reason = UnsafeGetReservedSlot(promise, PROMISE_RESULT_SLOT);
 
-        // Step 9.c.
-        if (UnsafeGetInt32FromReservedSlot(promise, PROMISE_IS_HANDLED_SLOT) !==
-            PROMISE_IS_HANDLED_STATE_HANDLED)
-        {
-            HostPromiseRejectionTracker(promise, PROMISE_REJECTION_TRACKER_OPERATION_HANDLE);
-        }
-
-        // Step 9.d.
+        // Step 9.b.
         EnqueuePromiseReactionJob(rejectReaction, reason);
     }
 
     // Step 10.
-    UnsafeSetReservedSlot(promise, PROMISE_IS_HANDLED_SLOT, PROMISE_IS_HANDLED_STATE_HANDLED);
-
-    // Step 11.
     return resultCapability.promise;
 }
 
 /// Utility functions below.
 function IsPromiseReaction(record) {
     return std_Reflect_getPrototypeOf(record) === PromiseReactionRecordProto;
 }
 
--- a/js/src/builtin/SelfHostingDefines.h
+++ b/js/src/builtin/SelfHostingDefines.h
@@ -63,32 +63,24 @@
 #define PROMISE_REJECT_REACTIONS_SLOT  3
 #define PROMISE_RESOLVE_FUNCTION_SLOT  4
 #define PROMISE_REJECT_FUNCTION_SLOT   5
 #define PROMISE_ALLOCATION_SITE_SLOT   6
 #define PROMISE_RESOLUTION_SITE_SLOT   7
 #define PROMISE_ALLOCATION_TIME_SLOT   8
 #define PROMISE_RESOLUTION_TIME_SLOT   9
 #define PROMISE_ID_SLOT               10
-#define PROMISE_IS_HANDLED_SLOT       11
 
 #define PROMISE_STATE_PENDING   0
 #define PROMISE_STATE_FULFILLED 1
 #define PROMISE_STATE_REJECTED  2
 
-#define PROMISE_IS_HANDLED_STATE_HANDLED   0
-#define PROMISE_IS_HANDLED_STATE_UNHANDLED 1
-#define PROMISE_IS_HANDLED_STATE_REPORTED  2
-
 #define PROMISE_HANDLER_IDENTITY 0
 #define PROMISE_HANDLER_THROWER  1
 
-#define PROMISE_REJECTION_TRACKER_OPERATION_REJECT false
-#define PROMISE_REJECTION_TRACKER_OPERATION_HANDLE true
-
 // NB: keep these in sync with the copy in jsfriendapi.h.
 #define JSITER_OWNONLY    0x8   /* iterate over obj's own properties only */
 #define JSITER_HIDDEN     0x10  /* also enumerate non-enumerable properties */
 #define JSITER_SYMBOLS    0x20  /* also include symbol property keys */
 #define JSITER_SYMBOLSONLY 0x40 /* exclude string property keys */
 
 #define TELEMETRY_DEFINE_GETTER_SETTER_THIS_NULL_UNDEFINED 25
 
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/inspect-wrapped-promise.js
+++ /dev/null
@@ -1,36 +0,0 @@
-if (typeof Promise === "undefined")
-    quit(0);
-
-let g = newGlobal();
-let dbg = new Debugger();
-let gw = dbg.addDebuggee(g);
-
-g.promise = Promise.resolve(42);
-
-let promiseDO = gw.getOwnPropertyDescriptor('promise').value;
-
-assertEq(promiseDO.isPromise, true);
-
-let state = promiseDO.promiseState;
-assertEq(state.state, "fulfilled");
-assertEq(state.value, 42);
-assertEq("reason" in state, true);
-assertEq(state.reason, undefined);
-
-let allocationSite = promiseDO.promiseAllocationSite;
-// Depending on whether async stacks are activated, this can be null, which
-// has typeof null.
-assertEq(typeof allocationSite === "object", true);
-
-let resolutionSite = promiseDO.promiseResolutionSite;
-// Depending on whether async stacks are activated, this can be null, which
-// has typeof null.
-assertEq(typeof resolutionSite === "object", true);
-
-assertEq(promiseDO.promiseID, 1);
-
-assertEq(typeof promiseDO.promiseDependentPromises, "object");
-assertEq(promiseDO.promiseDependentPromises.length, 0);
-
-assertEq(typeof promiseDO.promiseLifetime, "number");
-assertEq(typeof promiseDO.promiseTimeToResolution, "number");
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -4640,24 +4640,16 @@ JS_GetInterruptCallback(JSRuntime* rt)
 JS_PUBLIC_API(void)
 JS::SetEnqueuePromiseJobCallback(JSRuntime* rt, JSEnqueuePromiseJobCallback callback,
                                  void* data /* = nullptr */)
 {
     rt->enqueuePromiseJobCallback = callback;
     rt->enqueuePromiseJobCallbackData = data;
 }
 
-extern JS_PUBLIC_API(void)
-JS::SetPromiseRejectionTrackerCallback(JSRuntime* rt, JSPromiseRejectionTrackerCallback callback,
-                                       void* data /* = nullptr */)
-{
-    rt->promiseRejectionTrackerCallback = callback;
-    rt->promiseRejectionTrackerCallbackData = data;
-}
-
 JS_PUBLIC_API(JSObject*)
 JS::NewPromiseObject(JSContext* cx, HandleObject executor, HandleObject proto /* = nullptr */)
 {
     MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
     MOZ_ASSERT(IsCallable(executor));
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
@@ -4689,17 +4681,17 @@ JS::GetPromisePrototype(JSContext* cx)
 
 JS_PUBLIC_API(JS::PromiseState)
 JS::GetPromiseState(JS::HandleObject obj)
 {
     JSObject* promise = CheckedUnwrap(obj);
     return promise->as<PromiseObject>().state();
 }
 
-JS_PUBLIC_API(uint64_t)
+JS_PUBLIC_API(double)
 JS::GetPromiseID(JS::HandleObject promise)
 {
     return promise->as<PromiseObject>().getID();
 }
 
 JS_PUBLIC_API(JS::Value)
 JS::GetPromiseResult(JS::HandleObject promiseObj)
 {
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -598,30 +598,17 @@ typedef void
 
 typedef void
 (* JSWeakPointerCompartmentCallback)(JSRuntime* rt, JSCompartment* comp, void* data);
 
 typedef bool
 (* JSInterruptCallback)(JSContext* cx);
 
 typedef bool
-(* JSEnqueuePromiseJobCallback)(JSContext* cx, JS::HandleObject job,
-                                JS::HandleObject allocationSite, void* data);
-
-enum class PromiseRejectionHandlingState {
-    Unhandled,
-    Handled
-};
-
-typedef void
-(* JSPromiseRejectionTrackerCallback)(JSContext* cx, JS::HandleObject promise,
-                                      PromiseRejectionHandlingState state, void* data);
-
-typedef void
-(* JSProcessPromiseCallback)(JSContext* cx, JS::HandleObject promise);
+(* JSEnqueuePromiseJobCallback)(JSContext* cx, JS::HandleObject job, void* data);
 
 typedef void
 (* JSErrorReporter)(JSContext* cx, const char* message, JSErrorReport* report);
 
 /**
  * Possible exception types. These types are part of a JSErrorFormatString
  * structure. They define which error to throw in case of a runtime error.
  * JSEXN_NONE marks an unthrowable error.
@@ -4301,34 +4288,24 @@ JS_RequestInterruptCallback(JSRuntime* r
 
 namespace JS {
 
 /**
  * Sets the callback that's invoked whenever a Promise job should be enqeued.
  *
  * SpiderMonkey doesn't schedule Promise resolution jobs itself; instead,
  * using this function the embedding can provide a callback to do that
- * scheduling. The provided `callback` is invoked with the promise job,
- * the corresponding Promise's allocation stack, and the `data` pointer
- * passed here as arguments.
+ * scheduling. The provided `callback` is invoked with the promise job
+ * and the `data` pointer passed here as arguments.
  */
 extern JS_PUBLIC_API(void)
 SetEnqueuePromiseJobCallback(JSRuntime* rt, JSEnqueuePromiseJobCallback callback,
                              void* data = nullptr);
 
 /**
- * Sets the callback that's invoked whenever a Promise is rejected without
- * a rejection handler, and when a Promise that was previously rejected
- * without a handler gets a handler attached.
- */
-extern JS_PUBLIC_API(void)
-SetPromiseRejectionTrackerCallback(JSRuntime* rt, JSPromiseRejectionTrackerCallback callback,
-                                   void* data = nullptr);
-
-/**
  * Returns a new instance of the Promise builtin class in the current
  * compartment, with the right slot layout. If a `proto` is passed, that gets
  * set as the instance's [[Prototype]] instead of the original value of
  * `Promise.prototype`.
  */
 extern JS_PUBLIC_API(JSObject*)
 NewPromiseObject(JSContext* cx, JS::HandleObject executor, JS::HandleObject proto = nullptr);
 
@@ -4362,17 +4339,17 @@ enum class PromiseState {
  * Returns the given Promise's state as a JS::PromiseState enum value.
  */
 extern JS_PUBLIC_API(PromiseState)
 GetPromiseState(JS::HandleObject promise);
 
 /**
  * Returns the given Promise's process-unique ID.
  */
-JS_PUBLIC_API(uint64_t)
+JS_PUBLIC_API(double)
 GetPromiseID(JS::HandleObject promise);
 
 /**
  * Returns the given Promise's result: either the resolution value for
  * fulfilled promises, or the rejection reason for rejected ones.
  */
 extern JS_PUBLIC_API(JS::Value)
 GetPromiseResult(JS::HandleObject promise);
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -134,32 +134,35 @@ static const size_t gMaxStackSize = 128 
 static const double MAX_TIMEOUT_INTERVAL = 1800.0;
 
 #ifdef NIGHTLY_BUILD
 # define SHARED_MEMORY_DEFAULT 1
 #else
 # define SHARED_MEMORY_DEFAULT 0
 #endif
 
+#ifdef SPIDERMONKEY_PROMISE
 using JobQueue = GCVector<JSObject*, 0, SystemAllocPolicy>;
+#endif // SPIDERMONKEY_PROMISE
 
 // Per-runtime shell state.
 struct ShellRuntime
 {
     explicit ShellRuntime(JSRuntime* rt);
 
     bool isWorker;
     double timeoutInterval;
     Atomic<bool> serviceInterrupt;
     Atomic<bool> haveInterruptFunc;
     JS::PersistentRootedValue interruptFunc;
     bool lastWarningEnabled;
     JS::PersistentRootedValue lastWarning;
-    JS::PersistentRootedValue promiseRejectionTrackerCallback;
+#ifdef SPIDERMONKEY_PROMISE
     JS::PersistentRooted<JobQueue> jobQueue;
+#endif // SPIDERMONKEY_PROMISE
 
     /*
      * Watchdog thread state.
      */
     PRLock* watchdogLock;
     PRCondVar* watchdogWakeup;
     PRThread* watchdogThread;
     bool watchdogHasTimeout;
@@ -297,17 +300,16 @@ extern JS_EXPORT_API(void)   add_history
 ShellRuntime::ShellRuntime(JSRuntime* rt)
   : isWorker(false),
     timeoutInterval(-1.0),
     serviceInterrupt(false),
     haveInterruptFunc(false),
     interruptFunc(rt, NullValue()),
     lastWarningEnabled(false),
     lastWarning(rt, NullValue()),
-    promiseRejectionTrackerCallback(rt, NullValue()),
     watchdogLock(nullptr),
     watchdogWakeup(nullptr),
     watchdogThread(nullptr),
     watchdogHasTimeout(false),
     watchdogTimeout(0),
     sleepWakeup(nullptr),
     exitCode(0),
     quitting(false),
@@ -617,19 +619,19 @@ RunModule(JSContext* cx, const char* fil
 
     RootedValue value(cx);
     if (!JS_CallFunction(cx, loaderObj, importFun, args, &value)) {
         sr->exitCode = EXITCODE_RUNTIME_ERROR;
         return;
     }
 }
 
-static bool
-ShellEnqueuePromiseJobCallback(JSContext* cx, JS::HandleObject job, JS::HandleObject allocationSite,
-                               void* data)
+#ifdef SPIDERMONKEY_PROMISE
+static bool
+ShellEnqueuePromiseJobCallback(JSContext* cx, JS::HandleObject job, void* data)
 {
     ShellRuntime* sr = GetShellRuntime(cx);
     MOZ_ASSERT(job);
     return sr->jobQueue.append(job);
 }
 
 static bool
 DrainJobQueue(JSContext* cx)
@@ -659,61 +661,17 @@ DrainJobQueue(JSContext* cx, unsigned ar
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (!DrainJobQueue(cx))
         return false;
     args.rval().setUndefined();
     return true;
 }
-
-static void
-ForwardingPromiseRejectionTrackerCallback(JSContext* cx, JS::HandleObject promise,
-                                          PromiseRejectionHandlingState state, void* data)
-{
-    RootedValue callback(cx, GetShellRuntime(cx)->promiseRejectionTrackerCallback);
-    if (callback.isNull()) {
-        return;
-    }
-
-    InvokeArgs args2(cx);
-    if (!args2.init(2)) {
-        JS_ClearPendingException(cx);
-        return;
-    }
-
-    args2.setCallee(callback);
-    args2.setThis(UndefinedValue());
-
-    args2[0].setObject(*promise);
-    args2[1].setInt32(static_cast<int32_t>(state));
-
-    if (!Invoke(cx, args2))
-        JS_ClearPendingException(cx);
-}
-
-static bool
-SetPromiseRejectionTrackerCallback(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    if (!IsCallable(args.get(0))) {
-        JS_ReportError(cx,
-                       "setPromiseRejectionTrackerCallback expects a function as its sole "
-                       "argument");
-        return false;
-    }
-
-    GetShellRuntime(cx)->promiseRejectionTrackerCallback = args[0];
-    JS::SetPromiseRejectionTrackerCallback(cx->runtime(),
-                                           ForwardingPromiseRejectionTrackerCallback);
-
-    args.rval().setUndefined();
-    return true;
-}
+#endif // SPIDERMONKEY_PROMISE
 
 static bool
 EvalAndPrint(JSContext* cx, const char* bytes, size_t length,
              int lineno, bool compileOnly)
 {
     // Eval.
     JS::CompileOptions options(cx);
     options.setIntroductionType("js shell interactive")
@@ -802,17 +760,19 @@ ReadEvalPrintLoop(JSContext* cx, FILE* i
         if (JS::ForceLexicalInitialization(cx, globalLexical) && gErrFile->isOpen()) {
             fputs("Warning: According to the standard, after the above exception,\n"
                   "Warning: the global bindings should be permanently uninitialized.\n"
                   "Warning: We have non-standard-ly initialized them to `undefined`"
                   "for you.\nWarning: This nicety only happens in the JS shell.\n",
                   stderr);
         }
 
+#ifdef SPIDERMONKEY_PROMISE
         DrainJobQueue(cx);
+#endif // SPIDERMONKEY_PROMISE
 
     } while (!hitEOF && !sr->quitting);
 
     if (gOutFile->isOpen())
         fprintf(gOutFile->fp, "\n");
 }
 
 enum FileKind
@@ -955,16 +915,17 @@ CreateMappedArrayBuffer(JSContext* cx, u
     RootedObject obj(cx, JS_NewMappedArrayBufferWithContents(cx, size, contents));
     if (!obj)
         return false;
 
     args.rval().setObject(*obj);
     return true;
 }
 
+#ifdef SPIDERMONKEY_PROMISE
 static bool
 AddPromiseReactions(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() != 3) {
         JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr,
                              args.length() < 3 ? JSSMSG_NOT_ENOUGH_ARGS : JSSMSG_TOO_MANY_ARGS,
@@ -993,16 +954,17 @@ AddPromiseReactions(JSContext* cx, unsig
     if (!onResolve || !onResolve->is<JSFunction>() || !onReject || !onReject->is<JSFunction>()) {
         JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr,
                              JSSMSG_INVALID_ARGS, "addPromiseReactions");
         return false;
     }
 
     return JS::AddPromiseReactions(cx, promise, onResolve, onReject);
 }
+#endif // SPIDERMONKEY_PROMISE
 
 static bool
 Options(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     JS::RuntimeOptions oldRuntimeOptions = JS::RuntimeOptionsRef(cx);
     for (unsigned i = 0; i < args.length(); i++) {
@@ -2955,18 +2917,20 @@ WorkerMain(void* arg)
 
     JSContext* cx = NewContext(rt);
     if (!cx) {
         JS_DestroyRuntime(rt);
         js_delete(input);
         return;
     }
 
+#ifdef SPIDERMONKEY_PROMISE
     sr->jobQueue.init(cx, JobQueue(SystemAllocPolicy()));
     JS::SetEnqueuePromiseJobCallback(rt, ShellEnqueuePromiseJobCallback);
+#endif // SPIDERMONKEY_PROMISE
 
     JS::SetLargeAllocationFailureCallback(rt, my_LargeAllocFailCallback, (void*)cx);
 
     do {
         JSAutoRequest ar(cx);
 
         JS::CompartmentOptions compartmentOptions;
         SetStandardCompartmentOptions(compartmentOptions);
@@ -2984,18 +2948,20 @@ WorkerMain(void* arg)
         if (!JS::Compile(cx, options, input->chars, input->length, &script))
             break;
         RootedValue result(cx);
         JS_ExecuteScript(cx, script, &result);
     } while (0);
 
     JS::SetLargeAllocationFailureCallback(rt, nullptr, nullptr);
 
+#ifdef SPIDERMONKEY_PROMISE
     JS::SetEnqueuePromiseJobCallback(rt, nullptr);
     sr->jobQueue.reset();
+#endif // SPIDERMONKEY_PROMISE
 
     DestroyContext(cx, false);
 
     KillWatchdog(rt);
 
     JS_DestroyRuntime(rt);
 
     js_delete(input);
@@ -5568,19 +5534,21 @@ static const JSFunctionSpecWithHelp shel
 "         principals of ~0 subsumes all other principals. The absence of a\n"
 "         principal is treated as if its bits were 0xffff, for subsumption\n"
 "         purposes. If this property is omitted, supply no principal."),
 
     JS_FN_HELP("createMappedArrayBuffer", CreateMappedArrayBuffer, 1, 0,
 "createMappedArrayBuffer(filename, [offset, [size]])",
 "  Create an array buffer that mmaps the given file."),
 
+#ifdef SPIDERMONKEY_PROMISE
     JS_FN_HELP("addPromiseReactions", AddPromiseReactions, 3, 0,
 "addPromiseReactions(promise, onResolve, onReject)",
 "  Calls the JS::AddPromiseReactions JSAPI function with the given arguments."),
+#endif // SPIDERMONKEY_PROMISE
 
     JS_FN_HELP("getMaxArgs", GetMaxArgs, 0, 0,
 "getMaxArgs()",
 "  Return the maximum number of supported args for a call."),
 
     JS_FN_HELP("objectEmulatingUndefined", ObjectEmulatingUndefined, 0, 0,
 "objectEmulatingUndefined()",
 "  Return a new object obj for which typeof obj === \"undefined\", obj == null\n"
@@ -5645,25 +5613,22 @@ static const JSFunctionSpecWithHelp shel
 "{ eval }: Apply JS::Evaluate to |params.eval|.\n"
 "\n"
 "The return value is an array of strings, with one element for each\n"
 "JavaScript invocation that occurred as a result of the given\n"
 "operation. Each element is the name of the function invoked, or the\n"
 "string 'eval:FILENAME' if the code was invoked by 'eval' or something\n"
 "similar.\n"),
 
+#ifdef SPIDERMONKEY_PROMISE
     JS_FN_HELP("drainJobQueue", DrainJobQueue, 0, 0,
 "drainJobQueue()",
 "Take jobs from the shell's job queue in FIFO order and run them until the\n"
 "queue is empty.\n"),
-
-    JS_FN_HELP("setPromiseRejectionTrackerCallback", SetPromiseRejectionTrackerCallback, 1, 0,
-"setPromiseRejectionTrackerCallback()",
-"Sets the callback to be invoked whenever a Promise rejection is unhandled\n"
-"or a previously-unhandled rejection becomes handled."),
+#endif // SPIDERMONKEY_PROMISE
 
     JS_FS_HELP_END
 };
 
 static const JSFunctionSpecWithHelp fuzzing_unsafe_functions[] = {
     JS_FN_HELP("clone", Clone, 1, 0,
 "clone(fun[, scope])",
 "  Clone function object."),
@@ -6763,17 +6728,19 @@ ProcessArgs(JSContext* cx, OptionParser*
 
     /* The |script| argument is processed after all options. */
     if (const char* path = op->getStringArg("script")) {
         Process(cx, path, false);
         if (sr->exitCode)
             return sr->exitCode;
     }
 
+#ifdef SPIDERMONKEY_PROMISE
     DrainJobQueue(cx);
+#endif // SPIDERMONKEY_PROMISE
 
     if (op->getBoolOption('i'))
         Process(cx, nullptr, true);
 
     return sr->exitCode ? sr->exitCode : EXIT_SUCCESS;
 }
 
 static bool
@@ -7446,18 +7413,20 @@ main(int argc, char** argv, char** envp)
 
     if (!InitWatchdog(rt))
         return 1;
 
     cx = NewContext(rt);
     if (!cx)
         return 1;
 
+#ifdef SPIDERMONKEY_PROMISE
     sr->jobQueue.init(cx, JobQueue(SystemAllocPolicy()));
     JS::SetEnqueuePromiseJobCallback(rt, ShellEnqueuePromiseJobCallback);
+#endif // SPIDERMONKEY_PROMISE
 
     JS_SetGCParameter(rt, JSGC_MODE, JSGC_MODE_INCREMENTAL);
 
     JS::SetLargeAllocationFailureCallback(rt, my_LargeAllocFailCallback, (void*)cx);
 
     // Set some parameters to allow incremental GC in low memory conditions,
     // as is done for the browser, except in more-deterministic builds or when
     // disabled by command line options.
@@ -7475,18 +7444,20 @@ main(int argc, char** argv, char** envp)
 
 #ifdef DEBUG
     if (OOM_printAllocationCount)
         printf("OOM max count: %" PRIu64 "\n", js::oom::counter);
 #endif
 
     JS::SetLargeAllocationFailureCallback(rt, nullptr, nullptr);
 
+#ifdef SPIDERMONKEY_PROMISE
     JS::SetEnqueuePromiseJobCallback(rt, nullptr);
     sr->jobQueue.reset();
+#endif // SPIDERMONKEY_PROMISE
 
     DestroyContext(cx, true);
 
     KillWatchdog(rt);
 
     KillWorkerThreads();
 
     DestructSharedArrayBufferMailbox();
deleted file mode 100644
--- a/js/src/tests/ecma_6/Promise/promise-rejection-tracking.js
+++ /dev/null
@@ -1,36 +0,0 @@
-// |reftest| skip-if(!xulRuntime.shell) -- needs setPromiseRejectionTrackerCallback
-
-if (!this.Promise) {
-    this.reportCompare && reportCompare(true,true);
-    quit(0);
-}
-
-const UNHANDLED = 0;
-const HANDLED   = 1;
-
-let rejections = new Map();
-function rejectionTracker(promise, state) {
-    rejections.set(promise, state);
-}
-setPromiseRejectionTrackerCallback(rejectionTracker);
-
-// Unhandled rejections are tracked.
-let reject;
-let p = new Promise((res_, rej_) => (reject = rej_));
-assertEq(rejections.has(p), false);
-reject('reason');
-assertEq(rejections.get(p), UNHANDLED);
-// Later handling updates the tracking.
-p.then(_=>_, _=>_);
-assertEq(rejections.get(p), HANDLED);
-
-rejections.clear();
-
-// Handled rejections aren't tracked at all.
-p = new Promise((res_, rej_) => (reject = rej_));
-assertEq(rejections.has(p), false);
-p.then(_=>_, _=>_);
-reject('reason');
-assertEq(rejections.has(p), false);
-
-this.reportCompare && reportCompare(true,true);
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -7541,27 +7541,25 @@ DebuggerObject_checkThis(JSContext* cx, 
     if (!obj)                                                                  \
         return false;                                                          \
     Debugger* dbg = Debugger::fromChildJSObject(obj);                          \
     obj = (JSObject*) obj->as<NativeObject>().getPrivate();                    \
     MOZ_ASSERT(obj)
 
 #define THIS_DEBUGOBJECT_PROMISE(cx, argc, vp, fnname, args, obj)                   \
    THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, fnname, args, obj);                      \
-   obj = CheckedUnwrap(obj);                                                        \
    if (!obj->is<PromiseObject>()) {                                                 \
        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,  \
                             "Debugger", "Promise", obj->getClass()->name);          \
        return false;                                                                \
    }                                                                                \
    Rooted<PromiseObject*> promise(cx, &obj->as<PromiseObject>());
 
 #define THIS_DEBUGOBJECT_OWNER_PROMISE(cx, argc, vp, fnname, args, dbg, obj)        \
    THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, fnname, args, dbg, obj);           \
-   obj = CheckedUnwrap(obj);                                                        \
    if (!obj->is<PromiseObject>()) {                                                 \
        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,  \
                             "Debugger", "Promise", obj->getClass()->name);          \
        return false;                                                                \
    }                                                                                \
    Rooted<PromiseObject*> promise(cx, &obj->as<PromiseObject>());
 
 static bool
@@ -7852,17 +7850,16 @@ null(CallArgs& args)
 }
 
 #ifdef SPIDERMONKEY_PROMISE
 static bool
 DebuggerObject_getIsPromise(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, "get isPromise", args, refobj);
 
-    refobj = CheckedUnwrap(refobj);
     args.rval().setBoolean(refobj->is<PromiseObject>());
     return true;
 }
 
 static bool
 DebuggerObject_getPromiseState(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT_OWNER_PROMISE(cx, argc, vp, "get promiseState", args, dbg, refobj);
@@ -7958,17 +7955,17 @@ DebuggerObject_getPromiseResolutionSite(
     return true;
 }
 
 static bool
 DebuggerObject_getPromiseID(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT_PROMISE(cx, argc, vp, "get promiseID", args, refobj);
 
-    args.rval().setNumber(double(promise->getID()));
+    args.rval().setNumber(promise->getID());
     return true;
 }
 
 static bool
 DebuggerObject_getPromiseDependentPromises(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT_OWNER_PROMISE(cx, argc, vp, "get promiseDependentPromises", args, dbg, refobj);
 
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -35,17 +35,16 @@
 #include "jsnativestack.h"
 #include "jsobj.h"
 #include "jsscript.h"
 #include "jswatchpoint.h"
 #include "jswin.h"
 #include "jswrapper.h"
 
 #include "asmjs/WasmSignalHandlers.h"
-#include "builtin/Promise.h"
 #include "jit/arm/Simulator-arm.h"
 #include "jit/arm64/vixl/Simulator-vixl.h"
 #include "jit/JitCompartment.h"
 #include "jit/mips32/Simulator-mips32.h"
 #include "jit/mips64/Simulator-mips64.h"
 #include "jit/PcScriptCache.h"
 #include "js/Date.h"
 #include "js/MemoryMetrics.h"
@@ -149,18 +148,16 @@ JSRuntime::JSRuntime(JSRuntime* parentRu
 #endif
     interrupt_(false),
     telemetryCallback(nullptr),
     handlingSegFault(false),
     handlingJitInterrupt_(false),
     interruptCallback(nullptr),
     enqueuePromiseJobCallback(nullptr),
     enqueuePromiseJobCallbackData(nullptr),
-    promiseRejectionTrackerCallback(nullptr),
-    promiseRejectionTrackerCallbackData(nullptr),
 #ifdef DEBUG
     exclusiveAccessOwner(nullptr),
     mainThreadHasExclusiveAccess(false),
 #endif
     numExclusiveThreads(0),
     numCompartments(0),
     localeCallbacks(nullptr),
     defaultLocale(nullptr),
@@ -762,50 +759,23 @@ FreeOp::~FreeOp()
     for (size_t i = 0; i < freeLaterList.length(); i++)
         free_(freeLaterList[i]);
 
     if (!jitPoisonRanges.empty())
         jit::ExecutableAllocator::poisonCode(runtime(), jitPoisonRanges);
 }
 
 bool
-JSRuntime::enqueuePromiseJob(JSContext* cx, HandleFunction job, HandleObject promise)
+JSRuntime::enqueuePromiseJob(JSContext* cx, HandleFunction job)
 {
     MOZ_ASSERT(cx->runtime()->enqueuePromiseJobCallback,
                "Must set a callback using JS_SetEnqeueuPromiseJobCallback before using Promises");
 
     void* data = cx->runtime()->enqueuePromiseJobCallbackData;
-    RootedObject allocationSite(cx);
-    if (promise)
-        allocationSite = JS::GetPromiseAllocationSite(promise);
-    return cx->runtime()->enqueuePromiseJobCallback(cx, job, allocationSite, data);
-}
-
-void
-JSRuntime::addUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise)
-{
-    MOZ_ASSERT(promise->is<PromiseObject>());
-    if (!cx->runtime()->promiseRejectionTrackerCallback)
-        return;
-
-    void* data = cx->runtime()->promiseRejectionTrackerCallbackData;
-    cx->runtime()->promiseRejectionTrackerCallback(cx, promise,
-                                                   PromiseRejectionHandlingState::Unhandled, data);
-}
-
-void
-JSRuntime::removeUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise)
-{
-    MOZ_ASSERT(promise->is<PromiseObject>());
-    if (!cx->runtime()->promiseRejectionTrackerCallback)
-        return;
-
-    void* data = cx->runtime()->promiseRejectionTrackerCallbackData;
-    cx->runtime()->promiseRejectionTrackerCallback(cx, promise,
-                                                   PromiseRejectionHandlingState::Handled, data);
+    return cx->runtime()->enqueuePromiseJobCallback(cx, job, data);
 }
 
 void
 JSRuntime::updateMallocCounter(size_t nbytes)
 {
     updateMallocCounter(nullptr, nbytes);
 }
 
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -592,18 +592,16 @@ class PerThreadData : public PerThreadDa
 #ifdef JS_SIMULATOR
     js::jit::Simulator* simulator() const;
 #endif
 };
 
 class AutoLockForExclusiveAccess;
 } // namespace js
 
-using PromiseList = js::GCVector<JSObject*, 0, js::SystemAllocPolicy>;
-
 struct JSRuntime : public JS::shadow::Runtime,
                    public js::MallocProvider<JSRuntime>
 {
     /*
      * Per-thread data for the main thread that is associated with
      * this JSRuntime, as opposed to any worker threads used in
      * parallel sections.  See definition of |PerThreadData| struct
      * above for more details.
@@ -903,19 +901,16 @@ struct JSRuntime : public JS::shadow::Ru
         return handlingJitInterrupt_;
     }
 
     JSInterruptCallback interruptCallback;
 
     JSEnqueuePromiseJobCallback enqueuePromiseJobCallback;
     void* enqueuePromiseJobCallbackData;
 
-    JSPromiseRejectionTrackerCallback promiseRejectionTrackerCallback;
-    void* promiseRejectionTrackerCallbackData;
-
 #ifdef DEBUG
     void assertCanLock(js::RuntimeLock which);
 #else
     void assertCanLock(js::RuntimeLock which) {}
 #endif
 
   private:
     /*
@@ -1014,19 +1009,17 @@ struct JSRuntime : public JS::shadow::Ru
     }
     bool hasJitRuntime() const {
         return !!jitRuntime_;
     }
     js::InterpreterStack& interpreterStack() {
         return interpreterStack_;
     }
 
-    bool enqueuePromiseJob(JSContext* cx, js::HandleFunction job, js::HandleObject promise);
-    void addUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
-    void removeUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
+    bool enqueuePromiseJob(JSContext* cx, js::HandleFunction job);
 
     //-------------------------------------------------------------------------
     // Self-hosting support
     //-------------------------------------------------------------------------
 
     bool initSelfHosting(JSContext* cx);
     void finishSelfHosting();
     void markSelfHostingGlobal(JSTracer* trc);
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -1554,98 +1554,30 @@ js::ReportIncompatibleSelfHostedMethod(J
                              funName, "method", InformalValueTypeName(args.thisv()));
     }
 
     return false;
 }
 
 // ES6, 25.4.1.6.
 static bool
-intrinsic_EnqueuePromiseReactionJob(JSContext* cx, unsigned argc, Value* vp)
+intrinsic_EnqueuePromiseJob(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    MOZ_ASSERT(args.length() == 2);
-    MOZ_ASSERT(args[0].toObject().as<NativeObject>().getDenseInitializedLength() == 4);
-
-    // When using JS::AddPromiseReactions, no actual promise is created, so we
-    // might not have one here.
-    RootedObject promise(cx);
-    if (args[1].isObject())
-        promise = UncheckedUnwrap(&args[1].toObject());
-
-#ifdef DEBUG
-    MOZ_ASSERT_IF(promise, promise->is<PromiseObject>());
-    RootedNativeObject jobArgs(cx, &args[0].toObject().as<NativeObject>());
-    MOZ_ASSERT((jobArgs->getDenseElement(0).isNumber() &&
-                (jobArgs->getDenseElement(0).toNumber() == PROMISE_HANDLER_IDENTITY ||
-                 jobArgs->getDenseElement(0).toNumber() == PROMISE_HANDLER_THROWER)) ||
-               jobArgs->getDenseElement(0).toObject().isCallable());
-    MOZ_ASSERT(jobArgs->getDenseElement(2).toObject().isCallable());
-    MOZ_ASSERT(jobArgs->getDenseElement(3).toObject().isCallable());
-#endif
-
-    RootedAtom funName(cx, cx->names().empty);
-    RootedFunction job(cx, NewNativeFunction(cx, PromiseReactionJob, 0, funName,
-                                             gc::AllocKind::FUNCTION_EXTENDED));
-    if (!job)
-        return false;
-
-    job->setExtendedSlot(0, args[0]);
-    if (!cx->runtime()->enqueuePromiseJob(cx, job, promise))
+    MOZ_ASSERT(args.length() == 1);
+    MOZ_ASSERT(args[0].isObject());
+    MOZ_ASSERT(args[0].toObject().is<JSFunction>());
+
+    RootedFunction job(cx, &args[0].toObject().as<JSFunction>());
+    if (!cx->runtime()->enqueuePromiseJob(cx, job))
         return false;
     args.rval().setUndefined();
     return true;
 }
 
-// ES6, 25.4.1.6.
-static bool
-intrinsic_EnqueuePromiseResolveThenableJob(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-#ifdef DEBUG
-    MOZ_ASSERT(args.length() == 2);
-    MOZ_ASSERT(args[0].toObject().as<NativeObject>().getDenseInitializedLength() == 3);
-    MOZ_ASSERT(UncheckedUnwrap(&args[1].toObject())->is<PromiseObject>());
-    RootedNativeObject jobArgs(cx, &args[0].toObject().as<NativeObject>());
-    MOZ_ASSERT(jobArgs->getDenseElement(0).toObject().isCallable());
-    MOZ_ASSERT(jobArgs->getDenseElement(1).isObject());
-    MOZ_ASSERT(UncheckedUnwrap(&jobArgs->getDenseElement(2).toObject())->is<PromiseObject>());
-#endif
-
-    RootedAtom funName(cx, cx->names().empty);
-    RootedFunction job(cx, NewNativeFunction(cx, PromiseResolveThenableJob, 0, funName,
-                                             gc::AllocKind::FUNCTION_EXTENDED));
-    if (!job)
-        return false;
-
-    job->setExtendedSlot(0, args[0]);
-    RootedObject promise(cx, CheckedUnwrap(&args[1].toObject()));
-    if (!cx->runtime()->enqueuePromiseJob(cx, job, promise))
-        return false;
-    args.rval().setUndefined();
-    return true;
-}
-
-// ES2016, February 12 draft, 25.4.1.9.
-static bool
-intrinsic_HostPromiseRejectionTracker(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    MOZ_ASSERT(args.length() == 2);
-    MOZ_ASSERT(args[0].toObject().is<PromiseObject>());
-
-    Rooted<PromiseObject*> promise(cx, &args[0].toObject().as<PromiseObject>());
-    mozilla::DebugOnly<bool> isHandled = args[1].toBoolean();
-    MOZ_ASSERT(isHandled, "HostPromiseRejectionTracker intrinsic currently only marks as handled");
-    cx->runtime()->removeUnhandledRejectedPromise(cx, promise);
-    args.rval().setUndefined();
-    return true;
-}
-
 /**
  * Returns the default locale as a well-formed, but not necessarily canonicalized,
  * BCP-47 language tag.
  */
 static bool
 intrinsic_RuntimeDefaultLocale(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -1997,22 +1929,46 @@ intrinsic_ModuleNamespaceExports(JSConte
  * resulting state has been set on the promise, and it's up to the debugger
  * to act on this signal in whichever way it wants.
  */
 static bool
 intrinsic_onPromiseSettled(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 1);
-    Rooted<PromiseObject*> promise(cx, &args[0].toObject().as<PromiseObject>());
-    promise->onSettled(cx);
+    RootedObject promise(cx, &args[0].toObject());
+    JS::dbg::onPromiseSettled(cx, promise);
     args.rval().setUndefined();
     return true;
 }
 
+/**
+ * Intrinsic used to tell the debugger about settled promises.
+ *
+ * This is invoked both when resolving and rejecting promises, after the
+ * resulting state has been set on the promise, and it's up to the debugger
+ * to act on this signal in whichever way it wants.
+ */
+static bool
+intrinsic_captureCurrentStack(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    MOZ_ASSERT(args.length() < 2);
+    unsigned maxFrameCount = 0;
+    if (args.length() == 1)
+        maxFrameCount = args[0].toInt32();
+
+    RootedObject stack(cx);
+    if (!JS::CaptureCurrentStack(cx, &stack, maxFrameCount))
+        return false;
+
+    args.rval().setObject(*stack);
+    return true;
+}
+
 // The self-hosting global isn't initialized with the normal set of builtins.
 // Instead, individual C++-implemented functions that're required by
 // self-hosted code are defined as global functions. Accessing these
 // functions via a content compartment's builtins would be unsafe, because
 // content script might have changed the builtins' prototypes' members.
 // Installing the whole set of builtins in the self-hosting compartment, OTOH,
 // would be wasteful: it increases memory usage and initialization time for
 // self-hosting compartment.
@@ -2238,19 +2194,17 @@ static const JSFunctionSpec intrinsic_fu
           CallNonGenericSelfhostedMethod<Is<StarGeneratorObject>>, 2, 0),
 
     JS_FN("IsWeakSet", intrinsic_IsInstanceOfBuiltin<WeakSetObject>, 1,0),
     JS_FN("CallWeakSetMethodIfWrapped",
           CallNonGenericSelfhostedMethod<Is<WeakSetObject>>, 2, 0),
 
     JS_FN("IsPromise",                      intrinsic_IsInstanceOfBuiltin<PromiseObject>, 1,0),
     JS_FN("IsWrappedPromise",               intrinsic_IsWrappedPromiseObject,     1, 0),
-    JS_FN("_EnqueuePromiseReactionJob",     intrinsic_EnqueuePromiseReactionJob,  2, 0),
-    JS_FN("_EnqueuePromiseResolveThenableJob", intrinsic_EnqueuePromiseResolveThenableJob, 2, 0),
-    JS_FN("HostPromiseRejectionTracker",    intrinsic_HostPromiseRejectionTracker,2, 0),
+    JS_FN("_EnqueuePromiseJob",             intrinsic_EnqueuePromiseJob,          1, 0),
     JS_FN("_GetOriginalPromiseConstructor", intrinsic_OriginalPromiseConstructor, 0, 0),
     JS_FN("RejectUnwrappedPromise",         intrinsic_RejectUnwrappedPromise,     2, 0),
     JS_FN("CallPromiseMethodIfWrapped",
           CallNonGenericSelfhostedMethod<Is<PromiseObject>>,      2,0),
 
     // See builtin/TypedObject.h for descriptors of the typedobj functions.
     JS_FN("NewOpaqueTypedObject",           js::NewOpaqueTypedObject, 1, 0),
     JS_FN("NewDerivedTypedObject",          js::NewDerivedTypedObject, 3, 0),
@@ -2333,16 +2287,17 @@ static const JSFunctionSpec intrinsic_fu
     JS_FN("SetModuleEvaluated", intrinsic_SetModuleEvaluated, 1, 0),
     JS_FN("EvaluateModule", intrinsic_EvaluateModule, 1, 0),
     JS_FN("IsModuleNamespace", intrinsic_IsInstanceOfBuiltin<ModuleNamespaceObject>, 1, 0),
     JS_FN("NewModuleNamespace", intrinsic_NewModuleNamespace, 2, 0),
     JS_FN("AddModuleNamespaceBinding", intrinsic_AddModuleNamespaceBinding, 4, 0),
     JS_FN("ModuleNamespaceExports", intrinsic_ModuleNamespaceExports, 1, 0),
 
     JS_FN("_dbg_onPromiseSettled", intrinsic_onPromiseSettled, 1, 0),
+    JS_FN("_dbg_captureCurrentStack", intrinsic_captureCurrentStack, 1, 0),
 
     JS_FS_END
 };
 
 void
 js::FillSelfHostingCompileOptions(CompileOptions& options)
 {
     /*
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -913,18 +913,18 @@ CycleCollectedJSRuntime::ContextCallback
   MOZ_ASSERT(JS_GetRuntime(aContext) == self->Runtime());
 
   return self->CustomContextCallback(aContext, aOperation);
 }
 
 class PromiseJobRunnable final : public nsRunnable
 {
 public:
-  PromiseJobRunnable(JS::HandleObject aCallback, JS::HandleObject aAllocationSite)
-    : mCallback(new PromiseJobCallback(aCallback, aAllocationSite, nullptr))
+  PromiseJobRunnable(JSContext* aCx, JS::HandleObject aCallback)
+    : mCallback(new PromiseJobCallback(aCx, aCallback, nullptr))
   {
   }
 
   virtual ~PromiseJobRunnable()
   {
   }
 
 protected:
@@ -941,24 +941,23 @@ protected:
 private:
   RefPtr<PromiseJobCallback> mCallback;
 };
 
 /* static */
 bool
 CycleCollectedJSRuntime::EnqueuePromiseJobCallback(JSContext* aCx,
                                                    JS::HandleObject aJob,
-                                                   JS::HandleObject aAllocationSite,
                                                    void* aData)
 {
   CycleCollectedJSRuntime* self = static_cast<CycleCollectedJSRuntime*>(aData);
   MOZ_ASSERT(JS_GetRuntime(aCx) == self->Runtime());
   MOZ_ASSERT(Get() == self);
 
-  nsCOMPtr<nsIRunnable> runnable = new PromiseJobRunnable(aJob, aAllocationSite);
+  nsCOMPtr<nsIRunnable> runnable = new PromiseJobRunnable(aCx, aJob);
   self->DispatchToMicroTask(runnable);
   return true;
 }
 
 struct JsGcTracer : public TraceCallbacks
 {
   virtual void Trace(JS::Heap<JS::Value>* aPtr, const char* aName,
                      void* aClosure) const override
--- a/xpcom/base/CycleCollectedJSRuntime.h
+++ b/xpcom/base/CycleCollectedJSRuntime.h
@@ -214,17 +214,16 @@ private:
                                           JS::GCNurseryProgress aProgress,
                                           JS::gcreason::Reason aReason);
   static void OutOfMemoryCallback(JSContext* aContext, void* aData);
   static void LargeAllocationFailureCallback(void* aData);
   static bool ContextCallback(JSContext* aCx, unsigned aOperation,
                               void* aData);
   static bool EnqueuePromiseJobCallback(JSContext* aCx,
                                         JS::HandleObject aJob,
-                                        JS::HandleObject aAllocationSite,
                                         void* aData);
 
   virtual void TraceNativeBlackRoots(JSTracer* aTracer) { };
   void TraceNativeGrayRoots(JSTracer* aTracer);
 
   void AfterProcessMicrotask(uint32_t aRecursionDepth);
 public:
   void ProcessStableStateQueue();