summaryrefslogtreecommitdiffstats
path: root/js/src/builtin/Promise.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/builtin/Promise.h')
-rw-r--r--js/src/builtin/Promise.h191
1 files changed, 191 insertions, 0 deletions
diff --git a/js/src/builtin/Promise.h b/js/src/builtin/Promise.h
new file mode 100644
index 000000000..bb4778631
--- /dev/null
+++ b/js/src/builtin/Promise.h
@@ -0,0 +1,191 @@
+/* -*- 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 builtin_Promise_h
+#define builtin_Promise_h
+
+#include "builtin/SelfHostingDefines.h"
+#include "vm/NativeObject.h"
+
+namespace js {
+
+enum PromiseSlots {
+ PromiseSlot_Flags = 0,
+ PromiseSlot_ReactionsOrResult,
+ PromiseSlot_RejectFunction,
+ PromiseSlot_AwaitGenerator = PromiseSlot_RejectFunction,
+ PromiseSlot_AllocationSite,
+ PromiseSlot_ResolutionSite,
+ PromiseSlot_AllocationTime,
+ PromiseSlot_ResolutionTime,
+ PromiseSlot_Id,
+ PromiseSlots,
+};
+
+#define PROMISE_FLAG_RESOLVED 0x1
+#define PROMISE_FLAG_FULFILLED 0x2
+#define PROMISE_FLAG_HANDLED 0x4
+#define PROMISE_FLAG_REPORTED 0x8
+#define PROMISE_FLAG_DEFAULT_RESOLVE_FUNCTION 0x10
+#define PROMISE_FLAG_DEFAULT_REJECT_FUNCTION 0x20
+#define PROMISE_FLAG_ASYNC 0x40
+
+class AutoSetNewObjectMetadata;
+
+class PromiseObject : public NativeObject
+{
+ public:
+ static const unsigned RESERVED_SLOTS = PromiseSlots;
+ static const Class class_;
+ static const Class protoClass_;
+ static PromiseObject* create(JSContext* cx, HandleObject executor,
+ HandleObject proto = nullptr, bool needsWrapping = false);
+
+ static JSObject* unforgeableResolve(JSContext* cx, HandleValue value);
+ static JSObject* unforgeableReject(JSContext* cx, HandleValue value);
+
+ JS::PromiseState state() {
+ int32_t flags = getFixedSlot(PromiseSlot_Flags).toInt32();
+ if (!(flags & PROMISE_FLAG_RESOLVED)) {
+ MOZ_ASSERT(!(flags & PROMISE_FLAG_FULFILLED));
+ return JS::PromiseState::Pending;
+ }
+ if (flags & PROMISE_FLAG_FULFILLED)
+ return JS::PromiseState::Fulfilled;
+ return JS::PromiseState::Rejected;
+ }
+ Value value() {
+ MOZ_ASSERT(state() == JS::PromiseState::Fulfilled);
+ return getFixedSlot(PromiseSlot_ReactionsOrResult);
+ }
+ Value reason() {
+ MOZ_ASSERT(state() == JS::PromiseState::Rejected);
+ return getFixedSlot(PromiseSlot_ReactionsOrResult);
+ }
+
+ MOZ_MUST_USE bool resolve(JSContext* cx, HandleValue resolutionValue);
+ MOZ_MUST_USE bool reject(JSContext* cx, HandleValue rejectionValue);
+
+ void onSettled(JSContext* cx);
+
+ double allocationTime() { return getFixedSlot(PromiseSlot_AllocationTime).toNumber(); }
+ double resolutionTime() { return getFixedSlot(PromiseSlot_ResolutionTime).toNumber(); }
+ JSObject* allocationSite() {
+ return getFixedSlot(PromiseSlot_AllocationSite).toObjectOrNull();
+ }
+ JSObject* resolutionSite() {
+ return getFixedSlot(PromiseSlot_ResolutionSite).toObjectOrNull();
+ }
+ double lifetime();
+ double timeToResolution() {
+ MOZ_ASSERT(state() != JS::PromiseState::Pending);
+ return resolutionTime() - allocationTime();
+ }
+ MOZ_MUST_USE bool dependentPromises(JSContext* cx, MutableHandle<GCVector<Value>> values);
+ uint64_t getID();
+ bool isUnhandled() {
+ MOZ_ASSERT(state() == JS::PromiseState::Rejected);
+ return !(getFixedSlot(PromiseSlot_Flags).toInt32() & PROMISE_FLAG_HANDLED);
+ }
+ void markAsReported() {
+ MOZ_ASSERT(isUnhandled());
+ int32_t flags = getFixedSlot(PromiseSlot_Flags).toInt32();
+ setFixedSlot(PromiseSlot_Flags, Int32Value(flags | PROMISE_FLAG_REPORTED));
+ }
+};
+
+/**
+ * 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`.
+ */
+MOZ_MUST_USE JSObject*
+GetWaitForAllPromise(JSContext* cx, const JS::AutoObjectVector& promises);
+
+/**
+ * Enqueues resolve/reject reactions in the given Promise's reactions lists
+ * as though calling the original value of Promise.prototype.then.
+ *
+ * If the `createDependent` flag is not set, no dependent Promise will be
+ * created. This is used internally to implement DOM functionality.
+ * Note: In this case, the reactions pushed using this function contain a
+ * `promise` field that can contain null. That field is only ever used by
+ * devtools, which have to treat these reactions specially.
+ */
+MOZ_MUST_USE bool
+OriginalPromiseThen(JSContext* cx, Handle<PromiseObject*> promise,
+ HandleValue onFulfilled, HandleValue onRejected,
+ MutableHandleObject dependent, bool createDependent);
+
+
+MOZ_MUST_USE PromiseObject*
+CreatePromiseObjectForAsync(JSContext* cx, HandleValue generatorVal);
+
+MOZ_MUST_USE bool
+AsyncFunctionReturned(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value);
+
+MOZ_MUST_USE bool
+AsyncFunctionThrown(JSContext* cx, Handle<PromiseObject*> resultPromise);
+
+MOZ_MUST_USE bool
+AsyncFunctionAwait(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value);
+
+/**
+ * A PromiseTask represents a task that can be dispatched to a helper thread
+ * (via StartPromiseTask), executed (by implementing PromiseTask::execute()),
+ * and then resolved back on the original JSContext owner thread.
+ * Because it contains a PersistentRooted, a PromiseTask will only be destroyed
+ * on the JSContext's owner thread.
+ */
+class PromiseTask : public JS::AsyncTask
+{
+ JSRuntime* runtime_;
+ PersistentRooted<PromiseObject*> promise_;
+
+ // PromiseTask implements JS::AsyncTask and prevents derived classes from
+ // overriding; derived classes should implement the new pure virtual
+ // functions introduced below. Both of these methods 'delete this'.
+ void finish(JSContext* cx) override final;
+ void cancel(JSContext* cx) override final;
+
+ protected:
+ // Called by PromiseTask on the JSContext's owner thread after execute()
+ // completes on the helper thread, assuming JS::FinishAsyncTaskCallback
+ // succeeds. After this method returns, the task will be deleted.
+ virtual bool finishPromise(JSContext* cx, Handle<PromiseObject*> promise) = 0;
+
+ public:
+ PromiseTask(JSContext* cx, Handle<PromiseObject*> promise);
+ ~PromiseTask();
+ JSRuntime* runtime() const { return runtime_; }
+
+ // Called on a helper thread after StartAsyncTask. After execute()
+ // completes, the JS::FinishAsyncTaskCallback will be called. If this fails
+ // the task will be enqueued for deletion at some future point without ever
+ // calling finishPromise().
+ virtual void execute() = 0;
+
+ // May be called in the absence of helper threads to synchronously execute
+ // and finish a PromiseTask.
+ bool executeAndFinish(JSContext* cx);
+};
+
+bool
+Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp);
+bool
+Promise_reject(JSContext* cx, unsigned argc, Value* vp);
+bool
+Promise_then(JSContext* cx, unsigned argc, Value* vp);
+
+} // namespace js
+
+#endif /* builtin_Promise_h */