Bug 1510768: Move SpiderMonkey promise interface into its own header. r=arai
authorJim Blandy <jimb@mozilla.com>
Mon, 17 Dec 2018 23:21:04 +0000
changeset 508122 adcf05cc20255510741620dabdbf442a1d3ed0b1
parent 508121 6e0214071eabc06c35c92b931adcfdb798feb21f
child 508123 783c3d03caa650e3dc2e7699ba4b08786f45ba6f
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersarai
bugs1510768
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1510768: Move SpiderMonkey promise interface into its own header. r=arai Move js/src/jsapi.h declarations related to promises and job queues into their own public header file, js/public/Promise.h. Change the compilation units that need these declarations to #include the new header. There should be no changes to the actual functionality here, simply moving the code to a new file, and removing the "JS" prefix from some typedefs which are now in the JS namespace. Differential Revision: https://phabricator.services.mozilla.com/D13345
js/public/Promise.h
js/src/builtin/Promise.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/moz.build
js/src/vm/JSContext.h
xpcom/base/CycleCollectedJSContext.h
new file mode 100644
--- /dev/null
+++ b/js/public/Promise.h
@@ -0,0 +1,342 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef js_Promise_h
+#define js_Promise_h
+
+#include "jspubtd.h"
+#include "js/RootingAPI.h"
+#include "js/TypeDecls.h"
+
+namespace JS {
+
+typedef JSObject* (*GetIncumbentGlobalCallback)(JSContext* cx);
+
+typedef bool (*EnqueuePromiseJobCallback)(JSContext* cx,
+                                          JS::HandleObject promise,
+                                          JS::HandleObject job,
+                                          JS::HandleObject allocationSite,
+                                          JS::HandleObject incumbentGlobal,
+                                          void* data);
+
+enum class PromiseRejectionHandlingState { Unhandled, Handled };
+
+typedef void (*PromiseRejectionTrackerCallback)(
+    JSContext* cx, JS::HandleObject promise,
+    JS::PromiseRejectionHandlingState state, void* data);
+
+/**
+ * Sets the callback that's invoked whenever an incumbent global is required.
+ *
+ * SpiderMonkey doesn't itself have a notion of incumbent globals as defined
+ * by the html spec, so we need the embedding to provide this.
+ * See dom/base/ScriptSettings.h for details.
+ */
+extern JS_PUBLIC_API void SetGetIncumbentGlobalCallback(
+    JSContext* cx, GetIncumbentGlobalCallback callback);
+
+/**
+ * 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.
+ */
+extern JS_PUBLIC_API void SetEnqueuePromiseJobCallback(
+    JSContext* cx, EnqueuePromiseJobCallback 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(
+    JSContext* cx, PromiseRejectionTrackerCallback callback,
+    void* data = nullptr);
+
+/**
+ * Inform the runtime that the job queue is empty and the embedding is going to
+ * execute its last promise job. The runtime may now choose to skip creating
+ * promise jobs for asynchronous execution and instead continue execution
+ * synchronously. More specifically, this optimization is used to skip the
+ * standard job queuing behavior for `await` operations in async functions.
+ *
+ * This function may be called before executing the last job in the job queue.
+ * When it was called, JobQueueMayNotBeEmpty must be called in order to restore
+ * the default job queuing behavior before the embedding enqueues its next job
+ * into the job queue.
+ */
+extern JS_PUBLIC_API void JobQueueIsEmpty(JSContext* cx);
+
+/**
+ * Inform the runtime that job queue is no longer empty. The runtime can now no
+ * longer skip creating promise jobs for asynchronous execution, because
+ * pending jobs in the job queue must be executed first to preserve the FIFO
+ * (first in - first out) property of the queue. This effectively undoes
+ * JobQueueIsEmpty and re-enables the standard job queuing behavior.
+ *
+ * This function must be called whenever enqueuing a job to the job queue when
+ * JobQueueIsEmpty was called previously.
+ */
+extern JS_PUBLIC_API void JobQueueMayNotBeEmpty(JSContext* cx);
+
+/**
+ * Returns a new instance of the Promise builtin class in the current
+ * compartment, with the right slot layout.
+ *
+ * The `executor` can be a `nullptr`. In that case, the only way to resolve or
+ * reject the returned promise is via the `JS::ResolvePromise` and
+ * `JS::RejectPromise` JSAPI functions.
+ *
+ * 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);
+
+/**
+ * Returns true if the given object is an unwrapped PromiseObject, false
+ * otherwise.
+ */
+extern JS_PUBLIC_API bool IsPromiseObject(JS::HandleObject obj);
+
+/**
+ * Returns the current compartment's original Promise constructor.
+ */
+extern JS_PUBLIC_API JSObject* GetPromiseConstructor(JSContext* cx);
+
+/**
+ * Returns the current compartment's original Promise.prototype.
+ */
+extern JS_PUBLIC_API JSObject* GetPromisePrototype(JSContext* cx);
+
+// Keep this in sync with the PROMISE_STATE defines in SelfHostingDefines.h.
+enum class PromiseState { Pending, Fulfilled, Rejected };
+
+/**
+ * Returns the given Promise's state as a JS::PromiseState enum value.
+ *
+ * Returns JS::PromiseState::Pending if the given object is a wrapper that
+ * can't safely be unwrapped.
+ */
+extern JS_PUBLIC_API PromiseState GetPromiseState(JS::HandleObject promise);
+
+/**
+ * Returns the given Promise's process-unique ID.
+ */
+JS_PUBLIC_API uint64_t 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);
+
+/**
+ * Returns whether the given promise's rejection is already handled or not.
+ *
+ * The caller must check the given promise is rejected before checking it's
+ * handled or not.
+ */
+extern JS_PUBLIC_API bool GetPromiseIsHandled(JS::HandleObject promise);
+
+/**
+ * Returns a js::SavedFrame linked list of the stack that lead to the given
+ * Promise's allocation.
+ */
+extern JS_PUBLIC_API JSObject* GetPromiseAllocationSite(
+    JS::HandleObject promise);
+
+extern JS_PUBLIC_API JSObject* GetPromiseResolutionSite(
+    JS::HandleObject promise);
+
+#ifdef DEBUG
+extern JS_PUBLIC_API void DumpPromiseAllocationSite(JSContext* cx,
+                                                    JS::HandleObject promise);
+
+extern JS_PUBLIC_API void DumpPromiseResolutionSite(JSContext* cx,
+                                                    JS::HandleObject promise);
+#endif
+
+/**
+ * Calls the current compartment's original Promise.resolve on the original
+ * Promise constructor, with `resolutionValue` passed as an argument.
+ */
+extern JS_PUBLIC_API JSObject* CallOriginalPromiseResolve(
+    JSContext* cx, JS::HandleValue resolutionValue);
+
+/**
+ * Calls the current compartment's original Promise.reject on the original
+ * Promise constructor, with `resolutionValue` passed as an argument.
+ */
+extern JS_PUBLIC_API JSObject* CallOriginalPromiseReject(
+    JSContext* cx, JS::HandleValue rejectionValue);
+
+/**
+ * Resolves the given Promise with the given `resolutionValue`.
+ *
+ * Calls the `resolve` function that was passed to the executor function when
+ * the Promise was created.
+ */
+extern JS_PUBLIC_API bool ResolvePromise(JSContext* cx,
+                                         JS::HandleObject promiseObj,
+                                         JS::HandleValue resolutionValue);
+
+/**
+ * Rejects the given `promise` with the given `rejectionValue`.
+ *
+ * Calls the `reject` function that was passed to the executor function when
+ * the Promise was created.
+ */
+extern JS_PUBLIC_API bool RejectPromise(JSContext* cx,
+                                        JS::HandleObject promiseObj,
+                                        JS::HandleValue rejectionValue);
+
+/**
+ * Calls the current compartment's original Promise.prototype.then on the
+ * given `promise`, with `onResolve` and `onReject` passed as arguments.
+ *
+ * Throws a TypeError if `promise` isn't a Promise (or possibly a different
+ * error if it's a security wrapper or dead object proxy).
+ *
+ * Asserts that `onFulfilled` and `onRejected` are each either callable or
+ * null.
+ */
+extern JS_PUBLIC_API JSObject* CallOriginalPromiseThen(
+    JSContext* cx, JS::HandleObject promise, JS::HandleObject onFulfilled,
+    JS::HandleObject onRejected);
+
+/**
+ * Unforgeable, optimized version of the JS builtin Promise.prototype.then.
+ *
+ * Takes a Promise instance and `onResolve`, `onReject` callables to enqueue
+ * as reactions for that promise. In difference to Promise.prototype.then,
+ * this doesn't create and return a new Promise instance.
+ *
+ * Throws a TypeError if `promise` isn't a Promise (or possibly a different
+ * error if it's a security wrapper or dead object proxy).
+ *
+ * Asserts that `onFulfilled` and `onRejected` are each either callable or
+ * null.
+ */
+extern JS_PUBLIC_API bool AddPromiseReactions(JSContext* cx,
+                                              JS::HandleObject promise,
+                                              JS::HandleObject onFulfilled,
+                                              JS::HandleObject onRejected);
+
+// This enum specifies whether a promise is expected to keep track of
+// information that is useful for embedders to implement user activation
+// behavior handling as specified in the HTML spec:
+// https://html.spec.whatwg.org/multipage/interaction.html#triggered-by-user-activation
+// By default, promises created by SpiderMonkey do not make any attempt to keep
+// track of information about whether an activation behavior was being processed
+// when the original promise in a promise chain was created.  If the embedder
+// sets either of the HadUserInteractionAtCreation or
+// DidntHaveUserInteractionAtCreation flags on a promise after creating it,
+// SpiderMonkey will propagate that flag to newly created promises when
+// processing Promise#then and will make it possible to query this flag off of a
+// promise further down the chain later using the
+// GetPromiseUserInputEventHandlingState() API.
+enum class PromiseUserInputEventHandlingState {
+  // Don't keep track of this state (default for all promises)
+  DontCare,
+  // Keep track of this state, the original promise in the chain was created
+  // while an activation behavior was being processed.
+  HadUserInteractionAtCreation,
+  // Keep track of this state, the original promise in the chain was created
+  // while an activation behavior was not being processed.
+  DidntHaveUserInteractionAtCreation
+};
+
+/**
+ * Returns the given Promise's activation behavior state flag per above as a
+ * JS::PromiseUserInputEventHandlingState value.  All promises are created with
+ * the DontCare state by default.
+ *
+ * Returns JS::PromiseUserInputEventHandlingState::DontCare if the given object
+ * is a wrapper that can't safely be unwrapped.
+ */
+extern JS_PUBLIC_API PromiseUserInputEventHandlingState
+GetPromiseUserInputEventHandlingState(JS::HandleObject promise);
+
+/**
+ * Sets the given Promise's activation behavior state flag per above as a
+ * JS::PromiseUserInputEventHandlingState value.
+ *
+ * Returns false if the given object is a wrapper that can't safely be
+ * unwrapped.
+ */
+extern JS_PUBLIC_API bool SetPromiseUserInputEventHandlingState(
+    JS::HandleObject promise, JS::PromiseUserInputEventHandlingState state);
+
+/**
+ * Unforgeable version of the JS builtin Promise.all.
+ *
+ * Takes an AutoObjectVector of Promise objects and returns a promise that's
+ * resolved with an array of resolution values when all those promises have
+ * been resolved, or rejected with the rejection value of the first rejected
+ * promise.
+ *
+ * Asserts that all objects in the `promises` vector are, maybe wrapped,
+ * instances of `Promise` or a subclass of `Promise`.
+ */
+extern JS_PUBLIC_API JSObject* GetWaitForAllPromise(
+    JSContext* cx, const JS::AutoObjectVector& promises);
+
+/**
+ * The Dispatchable interface allows the embedding to call SpiderMonkey
+ * on a JSContext thread when requested via DispatchToEventLoopCallback.
+ */
+class JS_PUBLIC_API Dispatchable {
+ protected:
+  // Dispatchables are created and destroyed by SpiderMonkey.
+  Dispatchable() = default;
+  virtual ~Dispatchable() = default;
+
+ public:
+  // ShuttingDown indicates that SpiderMonkey should abort async tasks to
+  // expedite shutdown.
+  enum MaybeShuttingDown { NotShuttingDown, ShuttingDown };
+
+  // Called by the embedding after DispatchToEventLoopCallback succeeds.
+  virtual void run(JSContext* cx, MaybeShuttingDown maybeShuttingDown) = 0;
+};
+
+/**
+ * DispatchToEventLoopCallback may be called from any thread, being passed the
+ * same 'closure' passed to InitDispatchToEventLoop() and Dispatchable from the
+ * same JSRuntime. If the embedding returns 'true', the embedding must call
+ * Dispatchable::run() on an active JSContext thread for the same JSRuntime on
+ * which 'closure' was registered. If DispatchToEventLoopCallback returns
+ * 'false', SpiderMonkey will assume a shutdown of the JSRuntime is in progress.
+ * This contract implies that, by the time the final JSContext is destroyed in
+ * the JSRuntime, the embedding must have (1) run all Dispatchables for which
+ * DispatchToEventLoopCallback returned true, (2) already started returning
+ * false from calls to DispatchToEventLoopCallback.
+ */
+
+typedef bool (*DispatchToEventLoopCallback)(void* closure,
+                                            Dispatchable* dispatchable);
+
+extern JS_PUBLIC_API void InitDispatchToEventLoop(
+    JSContext* cx, DispatchToEventLoopCallback callback, void* closure);
+
+/**
+ * When a JSRuntime is destroyed it implicitly cancels all async tasks in
+ * progress, releasing any roots held by the task. However, this is not soon
+ * enough for cycle collection, which needs to have roots dropped earlier so
+ * that the cycle collector can transitively remove roots for a future GC. For
+ * these and other cases, the set of pending async tasks can be canceled
+ * with this call earlier than JSRuntime destruction.
+ */
+
+extern JS_PUBLIC_API void ShutdownAsyncTasks(JSContext* cx);
+
+} // namespace JS
+
+#endif // js_Promise_h
--- a/js/src/builtin/Promise.h
+++ b/js/src/builtin/Promise.h
@@ -2,16 +2,18 @@
  * vim: set ts=8 sts=2 et sw=2 tw=80:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef builtin_Promise_h
 #define builtin_Promise_h
 
+#include "js/Promise.h"
+
 #include "builtin/SelfHostingDefines.h"
 #include "threading/ConditionVariable.h"
 #include "threading/Mutex.h"
 #include "vm/NativeObject.h"
 
 namespace js {
 
 enum PromiseSlots {
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3850,29 +3850,29 @@ JS_PUBLIC_API void JS_ResetInterruptCall
 }
 
 /************************************************************************/
 
 /*
  * Promises.
  */
 JS_PUBLIC_API void JS::SetGetIncumbentGlobalCallback(
-    JSContext* cx, JSGetIncumbentGlobalCallback callback) {
+    JSContext* cx, GetIncumbentGlobalCallback callback) {
   cx->getIncumbentGlobalCallback = callback;
 }
 
 JS_PUBLIC_API void JS::SetEnqueuePromiseJobCallback(
-    JSContext* cx, JSEnqueuePromiseJobCallback callback,
+    JSContext* cx, EnqueuePromiseJobCallback callback,
     void* data /* = nullptr */) {
   cx->enqueuePromiseJobCallback = callback;
   cx->enqueuePromiseJobCallbackData = data;
 }
 
 extern JS_PUBLIC_API void JS::SetPromiseRejectionTrackerCallback(
-    JSContext* cx, JSPromiseRejectionTrackerCallback callback,
+    JSContext* cx, PromiseRejectionTrackerCallback callback,
     void* data /* = nullptr */) {
   cx->promiseRejectionTrackerCallback = callback;
   cx->promiseRejectionTrackerCallbackData = data;
 }
 
 extern JS_PUBLIC_API void JS::JobQueueIsEmpty(JSContext* cx) {
   cx->canSkipEnqueuingJobs = true;
 }
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -164,35 +164,16 @@ class HandleValueArray {
 } /* namespace JS */
 
 /* Callbacks and their arguments. */
 
 /************************************************************************/
 
 typedef bool (*JSInterruptCallback)(JSContext* cx);
 
-typedef JSObject* (*JSGetIncumbentGlobalCallback)(JSContext* cx);
-
-typedef bool (*JSEnqueuePromiseJobCallback)(JSContext* cx,
-                                            JS::HandleObject promise,
-                                            JS::HandleObject job,
-                                            JS::HandleObject allocationSite,
-                                            JS::HandleObject incumbentGlobal,
-                                            void* data);
-
-namespace JS {
-
-enum class PromiseRejectionHandlingState { Unhandled, Handled };
-
-} /* namespace JS */
-
-typedef void (*JSPromiseRejectionTrackerCallback)(
-    JSContext* cx, JS::HandleObject promise,
-    JS::PromiseRejectionHandlingState state, void* data);
-
 /**
  * Callback used to ask the embedding for the cross compartment wrapper handler
  * that implements the desired prolicy for this kind of object in the
  * destination compartment. |obj| is the object to be wrapped. If |existing| is
  * non-nullptr, it will point to an existing wrapper object that should be
  * re-used if possible. |existing| is guaranteed to be a cross-compartment
  * wrapper with a lazily-defined prototype and the correct global. It is
  * guaranteed not to wrap a function.
@@ -3283,314 +3264,16 @@ extern JS_PUBLIC_API bool JS_DisableInte
 extern JS_PUBLIC_API void JS_ResetInterruptCallback(JSContext* cx, bool enable);
 
 extern JS_PUBLIC_API void JS_RequestInterruptCallback(JSContext* cx);
 
 extern JS_PUBLIC_API void JS_RequestInterruptCallbackCanWait(JSContext* cx);
 
 namespace JS {
 
-/**
- * Sets the callback that's invoked whenever an incumbent global is required.
- *
- * SpiderMonkey doesn't itself have a notion of incumbent globals as defined
- * by the html spec, so we need the embedding to provide this.
- * See dom/base/ScriptSettings.h for details.
- */
-extern JS_PUBLIC_API void SetGetIncumbentGlobalCallback(
-    JSContext* cx, JSGetIncumbentGlobalCallback callback);
-
-/**
- * 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.
- */
-extern JS_PUBLIC_API void SetEnqueuePromiseJobCallback(
-    JSContext* cx, 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(
-    JSContext* cx, JSPromiseRejectionTrackerCallback callback,
-    void* data = nullptr);
-
-/**
- * Inform the runtime that the job queue is empty and the embedding is going to
- * execute its last promise job. The runtime may now choose to skip creating
- * promise jobs for asynchronous execution and instead continue execution
- * synchronously. More specifically, this optimization is used to skip the
- * standard job queuing behavior for `await` operations in async functions.
- *
- * This function may be called before executing the last job in the job queue.
- * When it was called, JobQueueMayNotBeEmpty must be called in order to restore
- * the default job queuing behavior before the embedding enqueues its next job
- * into the job queue.
- */
-extern JS_PUBLIC_API void JobQueueIsEmpty(JSContext* cx);
-
-/**
- * Inform the runtime that job queue is no longer empty. The runtime can now no
- * longer skip creating promise jobs for asynchronous execution, because
- * pending jobs in the job queue must be executed first to preserve the FIFO
- * (first in - first out) property of the queue. This effectively undoes
- * JobQueueIsEmpty and re-enables the standard job queuing behavior.
- *
- * This function must be called whenever enqueuing a job to the job queue when
- * JobQueueIsEmpty was called previously.
- */
-extern JS_PUBLIC_API void JobQueueMayNotBeEmpty(JSContext* cx);
-
-/**
- * Returns a new instance of the Promise builtin class in the current
- * compartment, with the right slot layout.
- *
- * The `executor` can be a `nullptr`. In that case, the only way to resolve or
- * reject the returned promise is via the `JS::ResolvePromise` and
- * `JS::RejectPromise` JSAPI functions.
- *
- * 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);
-
-/**
- * Returns true if the given object is an unwrapped PromiseObject, false
- * otherwise.
- */
-extern JS_PUBLIC_API bool IsPromiseObject(JS::HandleObject obj);
-
-/**
- * Returns the current compartment's original Promise constructor.
- */
-extern JS_PUBLIC_API JSObject* GetPromiseConstructor(JSContext* cx);
-
-/**
- * Returns the current compartment's original Promise.prototype.
- */
-extern JS_PUBLIC_API JSObject* GetPromisePrototype(JSContext* cx);
-
-// Keep this in sync with the PROMISE_STATE defines in SelfHostingDefines.h.
-enum class PromiseState { Pending, Fulfilled, Rejected };
-
-/**
- * Returns the given Promise's state as a JS::PromiseState enum value.
- *
- * Returns JS::PromiseState::Pending if the given object is a wrapper that
- * can't safely be unwrapped.
- */
-extern JS_PUBLIC_API PromiseState GetPromiseState(JS::HandleObject promise);
-
-/**
- * Returns the given Promise's process-unique ID.
- */
-JS_PUBLIC_API uint64_t 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);
-
-/**
- * Returns whether the given promise's rejection is already handled or not.
- *
- * The caller must check the given promise is rejected before checking it's
- * handled or not.
- */
-extern JS_PUBLIC_API bool GetPromiseIsHandled(JS::HandleObject promise);
-
-/**
- * Returns a js::SavedFrame linked list of the stack that lead to the given
- * Promise's allocation.
- */
-extern JS_PUBLIC_API JSObject* GetPromiseAllocationSite(
-    JS::HandleObject promise);
-
-extern JS_PUBLIC_API JSObject* GetPromiseResolutionSite(
-    JS::HandleObject promise);
-
-#ifdef DEBUG
-extern JS_PUBLIC_API void DumpPromiseAllocationSite(JSContext* cx,
-                                                    JS::HandleObject promise);
-
-extern JS_PUBLIC_API void DumpPromiseResolutionSite(JSContext* cx,
-                                                    JS::HandleObject promise);
-#endif
-
-/**
- * Calls the current compartment's original Promise.resolve on the original
- * Promise constructor, with `resolutionValue` passed as an argument.
- */
-extern JS_PUBLIC_API JSObject* CallOriginalPromiseResolve(
-    JSContext* cx, JS::HandleValue resolutionValue);
-
-/**
- * Calls the current compartment's original Promise.reject on the original
- * Promise constructor, with `resolutionValue` passed as an argument.
- */
-extern JS_PUBLIC_API JSObject* CallOriginalPromiseReject(
-    JSContext* cx, JS::HandleValue rejectionValue);
-
-/**
- * Resolves the given Promise with the given `resolutionValue`.
- *
- * Calls the `resolve` function that was passed to the executor function when
- * the Promise was created.
- */
-extern JS_PUBLIC_API bool ResolvePromise(JSContext* cx,
-                                         JS::HandleObject promiseObj,
-                                         JS::HandleValue resolutionValue);
-
-/**
- * Rejects the given `promise` with the given `rejectionValue`.
- *
- * Calls the `reject` function that was passed to the executor function when
- * the Promise was created.
- */
-extern JS_PUBLIC_API bool RejectPromise(JSContext* cx,
-                                        JS::HandleObject promiseObj,
-                                        JS::HandleValue rejectionValue);
-
-/**
- * Calls the current compartment's original Promise.prototype.then on the
- * given `promise`, with `onResolve` and `onReject` passed as arguments.
- *
- * Throws a TypeError if `promise` isn't a Promise (or possibly a different
- * error if it's a security wrapper or dead object proxy).
- *
- * Asserts that `onFulfilled` and `onRejected` are each either callable or
- * null.
- */
-extern JS_PUBLIC_API JSObject* CallOriginalPromiseThen(
-    JSContext* cx, JS::HandleObject promise, JS::HandleObject onFulfilled,
-    JS::HandleObject onRejected);
-
-/**
- * Unforgeable, optimized version of the JS builtin Promise.prototype.then.
- *
- * Takes a Promise instance and `onResolve`, `onReject` callables to enqueue
- * as reactions for that promise. In difference to Promise.prototype.then,
- * this doesn't create and return a new Promise instance.
- *
- * Throws a TypeError if `promise` isn't a Promise (or possibly a different
- * error if it's a security wrapper or dead object proxy).
- *
- * Asserts that `onFulfilled` and `onRejected` are each either callable or
- * null.
- */
-extern JS_PUBLIC_API bool AddPromiseReactions(JSContext* cx,
-                                              JS::HandleObject promise,
-                                              JS::HandleObject onFulfilled,
-                                              JS::HandleObject onRejected);
-
-// This enum specifies whether a promise is expected to keep track of
-// information that is useful for embedders to implement user activation
-// behavior handling as specified in the HTML spec:
-// https://html.spec.whatwg.org/multipage/interaction.html#triggered-by-user-activation
-// By default, promises created by SpiderMonkey do not make any attempt to keep
-// track of information about whether an activation behavior was being processed
-// when the original promise in a promise chain was created.  If the embedder
-// sets either of the HadUserInteractionAtCreation or
-// DidntHaveUserInteractionAtCreation flags on a promise after creating it,
-// SpiderMonkey will propagate that flag to newly created promises when
-// processing Promise#then and will make it possible to query this flag off of a
-// promise further down the chain later using the
-// GetPromiseUserInputEventHandlingState() API.
-enum class PromiseUserInputEventHandlingState {
-  // Don't keep track of this state (default for all promises)
-  DontCare,
-  // Keep track of this state, the original promise in the chain was created
-  // while an activation behavior was being processed.
-  HadUserInteractionAtCreation,
-  // Keep track of this state, the original promise in the chain was created
-  // while an activation behavior was not being processed.
-  DidntHaveUserInteractionAtCreation
-};
-
-/**
- * Returns the given Promise's activation behavior state flag per above as a
- * JS::PromiseUserInputEventHandlingState value.  All promises are created with
- * the DontCare state by default.
- *
- * Returns JS::PromiseUserInputEventHandlingState::DontCare if the given object
- * is a wrapper that can't safely be unwrapped.
- */
-extern JS_PUBLIC_API PromiseUserInputEventHandlingState
-GetPromiseUserInputEventHandlingState(JS::HandleObject promise);
-
-/**
- * Sets the given Promise's activation behavior state flag per above as a
- * JS::PromiseUserInputEventHandlingState value.
- *
- * Returns false if the given object is a wrapper that can't safely be
- * unwrapped.
- */
-extern JS_PUBLIC_API bool SetPromiseUserInputEventHandlingState(
-    JS::HandleObject promise, JS::PromiseUserInputEventHandlingState state);
-
-/**
- * Unforgeable version of the JS builtin Promise.all.
- *
- * Takes an AutoObjectVector of Promise objects and returns a promise that's
- * resolved with an array of resolution values when all those promises have
- * been resolved, or rejected with the rejection value of the first rejected
- * promise.
- *
- * Asserts that all objects in the `promises` vector are, maybe wrapped,
- * instances of `Promise` or a subclass of `Promise`.
- */
-extern JS_PUBLIC_API JSObject* GetWaitForAllPromise(
-    JSContext* cx, const JS::AutoObjectVector& promises);
-
-/**
- * The Dispatchable interface allows the embedding to call SpiderMonkey
- * on a JSContext thread when requested via DispatchToEventLoopCallback.
- */
-class JS_PUBLIC_API Dispatchable {
- protected:
-  // Dispatchables are created and destroyed by SpiderMonkey.
-  Dispatchable() = default;
-  virtual ~Dispatchable() = default;
-
- public:
-  // ShuttingDown indicates that SpiderMonkey should abort async tasks to
-  // expedite shutdown.
-  enum MaybeShuttingDown { NotShuttingDown, ShuttingDown };
-
-  // Called by the embedding after DispatchToEventLoopCallback succeeds.
-  virtual void run(JSContext* cx, MaybeShuttingDown maybeShuttingDown) = 0;
-};
-
-/**
- * DispatchToEventLoopCallback may be called from any thread, being passed the
- * same 'closure' passed to InitDispatchToEventLoop() and Dispatchable from the
- * same JSRuntime. If the embedding returns 'true', the embedding must call
- * Dispatchable::run() on an active JSContext thread for the same JSRuntime on
- * which 'closure' was registered. If DispatchToEventLoopCallback returns
- * 'false', SpiderMonkey will assume a shutdown of the JSRuntime is in progress.
- * This contract implies that, by the time the final JSContext is destroyed in
- * the JSRuntime, the embedding must have (1) run all Dispatchables for which
- * DispatchToEventLoopCallback returned true, (2) already started returning
- * false from calls to DispatchToEventLoopCallback.
- */
-
-typedef bool (*DispatchToEventLoopCallback)(void* closure,
-                                            Dispatchable* dispatchable);
-
-extern JS_PUBLIC_API void InitDispatchToEventLoop(
-    JSContext* cx, DispatchToEventLoopCallback callback, void* closure);
-
 /* Vector of characters used for holding build ids. */
 
 typedef js::Vector<char, 0, js::SystemAllocPolicy> BuildIdCharVector;
 
 /**
  * The ConsumeStreamCallback is called from an active JSContext, passing a
  * StreamConsumer that wishes to consume the given host object as a stream of
  * bytes with the given MIME type. On failure, the embedding must report the
@@ -3678,27 +3361,16 @@ typedef bool (*ConsumeStreamCallback)(JS
 
 typedef void (*ReportStreamErrorCallback)(JSContext* cx, size_t errorCode);
 
 extern JS_PUBLIC_API void InitConsumeStreamCallback(
     JSContext* cx, ConsumeStreamCallback consume,
     ReportStreamErrorCallback report);
 
 /**
- * When a JSRuntime is destroyed it implicitly cancels all async tasks in
- * progress, releasing any roots held by the task. However, this is not soon
- * enough for cycle collection, which needs to have roots dropped earlier so
- * that the cycle collector can transitively remove roots for a future GC. For
- * these and other cases, the set of pending async tasks can be canceled
- * with this call earlier than JSRuntime destruction.
- */
-
-extern JS_PUBLIC_API void ShutdownAsyncTasks(JSContext* cx);
-
-/**
  * Supply an alternative stack to incorporate into captured SavedFrame
  * backtraces as the imputed caller of asynchronous JavaScript calls, like async
  * function resumptions and DOM callbacks.
  *
  * When one async function awaits the result of another, it's natural to think
  * of that as a sort of function call: just as execution resumes from an
  * ordinary call expression when the callee returns, with the return value
  * providing the value of the call expression, execution resumes from an 'await'
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -137,16 +137,17 @@ EXPORTS.js += [
     '../public/LocaleSensitive.h',
     '../public/MemoryFunctions.h',
     '../public/MemoryMetrics.h',
     '../public/OffThreadScriptCompilation.h',
     '../public/Principals.h',
     '../public/Printf.h',
     '../public/ProfilingFrameIterator.h',
     '../public/ProfilingStack.h',
+    '../public/Promise.h',
     '../public/ProtoKey.h',
     '../public/Proxy.h',
     '../public/Realm.h',
     '../public/RefCounted.h',
     '../public/RequiredDefines.h',
     '../public/Result.h',
     '../public/RootingAPI.h',
     '../public/SavedFrameAPI.h',
--- a/js/src/vm/JSContext.h
+++ b/js/src/vm/JSContext.h
@@ -9,16 +9,17 @@
 #ifndef vm_JSContext_h
 #define vm_JSContext_h
 
 #include "mozilla/MemoryReporting.h"
 
 #include "ds/TraceableFifo.h"
 #include "js/CharacterEncoding.h"
 #include "js/GCVector.h"
+#include "js/Promise.h"
 #include "js/Result.h"
 #include "js/Utility.h"
 #include "js/Vector.h"
 #include "threading/ProtectedData.h"
 #include "util/StructuredSpewer.h"
 #include "vm/ErrorReporting.h"
 #include "vm/MallocProvider.h"
 #include "vm/Runtime.h"
@@ -885,29 +886,29 @@ struct JSContext : public JS::RootingCon
   mozilla::Atomic<uintptr_t, mozilla::Relaxed,
                   mozilla::recordreplay::Behavior::DontPreserve>
       jitStackLimit;
 
   // Like jitStackLimit, but not reset to trigger interrupts.
   js::ThreadData<uintptr_t> jitStackLimitNoInterrupt;
 
   // Promise callbacks.
-  js::ThreadData<JSGetIncumbentGlobalCallback> getIncumbentGlobalCallback;
-  js::ThreadData<JSEnqueuePromiseJobCallback> enqueuePromiseJobCallback;
+  js::ThreadData<JS::GetIncumbentGlobalCallback> getIncumbentGlobalCallback;
+  js::ThreadData<JS::EnqueuePromiseJobCallback> enqueuePromiseJobCallback;
   js::ThreadData<void*> enqueuePromiseJobCallbackData;
 
   // Queue of pending jobs as described in ES2016 section 8.4.
   // Only used if internal job queue handling was activated using
   // `js::UseInternalJobQueues`.
   js::ThreadData<JS::PersistentRooted<js::JobQueue>*> jobQueue;
   js::ThreadData<bool> drainingJobQueue;
   js::ThreadData<bool> stopDrainingJobQueue;
   js::ThreadData<bool> canSkipEnqueuingJobs;
 
-  js::ThreadData<JSPromiseRejectionTrackerCallback>
+  js::ThreadData<JS::PromiseRejectionTrackerCallback>
       promiseRejectionTrackerCallback;
   js::ThreadData<void*> promiseRejectionTrackerCallbackData;
 
   JSObject* getIncumbentGlobal(JSContext* cx);
   bool enqueuePromiseJob(JSContext* cx, js::HandleFunction job,
                          js::HandleObject promise,
                          js::HandleObject incumbentGlobal);
   void addUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
--- a/xpcom/base/CycleCollectedJSContext.h
+++ b/xpcom/base/CycleCollectedJSContext.h
@@ -10,17 +10,17 @@
 #include <queue>
 
 #include "mozilla/DeferredFinalize.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/mozalloc.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/AtomList.h"
 #include "jsapi.h"
-#include "jsfriendapi.h"
+#include "js/Promise.h"
 
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsTArray.h"
 
 class nsCycleCollectionNoteRootCallback;
 class nsIRunnable;
 class nsThread;