Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef builtin_Promise_h
8 : #define builtin_Promise_h
9 :
10 : #include "builtin/SelfHostingDefines.h"
11 : #include "vm/NativeObject.h"
12 :
13 : namespace js {
14 :
15 : enum PromiseSlots {
16 : PromiseSlot_Flags = 0,
17 : PromiseSlot_ReactionsOrResult,
18 : PromiseSlot_RejectFunction,
19 : PromiseSlot_AwaitGenerator = PromiseSlot_RejectFunction,
20 : PromiseSlot_AllocationSite,
21 : PromiseSlot_ResolutionSite,
22 : PromiseSlot_AllocationTime,
23 : PromiseSlot_ResolutionTime,
24 : PromiseSlot_Id,
25 : PromiseSlots,
26 : };
27 :
28 : #define PROMISE_FLAG_RESOLVED 0x1
29 : #define PROMISE_FLAG_FULFILLED 0x2
30 : #define PROMISE_FLAG_HANDLED 0x4
31 : #define PROMISE_FLAG_REPORTED 0x8
32 : #define PROMISE_FLAG_DEFAULT_RESOLVE_FUNCTION 0x10
33 : #define PROMISE_FLAG_DEFAULT_REJECT_FUNCTION 0x20
34 : #define PROMISE_FLAG_ASYNC 0x40
35 :
36 : class AutoSetNewObjectMetadata;
37 :
38 : class PromiseObject : public NativeObject
39 : {
40 : public:
41 : static const unsigned RESERVED_SLOTS = PromiseSlots;
42 : static const Class class_;
43 : static const Class protoClass_;
44 : static PromiseObject* create(JSContext* cx, HandleObject executor,
45 : HandleObject proto = nullptr, bool needsWrapping = false);
46 :
47 : static PromiseObject* createSkippingExecutor(JSContext* cx);
48 :
49 : static JSObject* unforgeableResolve(JSContext* cx, HandleValue value);
50 : static JSObject* unforgeableReject(JSContext* cx, HandleValue value);
51 :
52 1228 : JS::PromiseState state() {
53 1228 : int32_t flags = getFixedSlot(PromiseSlot_Flags).toInt32();
54 1228 : if (!(flags & PROMISE_FLAG_RESOLVED)) {
55 961 : MOZ_ASSERT(!(flags & PROMISE_FLAG_FULFILLED));
56 961 : return JS::PromiseState::Pending;
57 : }
58 267 : if (flags & PROMISE_FLAG_FULFILLED)
59 259 : return JS::PromiseState::Fulfilled;
60 8 : return JS::PromiseState::Rejected;
61 : }
62 0 : Value value() {
63 0 : MOZ_ASSERT(state() == JS::PromiseState::Fulfilled);
64 0 : return getFixedSlot(PromiseSlot_ReactionsOrResult);
65 : }
66 0 : Value reason() {
67 0 : MOZ_ASSERT(state() == JS::PromiseState::Rejected);
68 0 : return getFixedSlot(PromiseSlot_ReactionsOrResult);
69 : }
70 :
71 : static MOZ_MUST_USE bool resolve(JSContext* cx, Handle<PromiseObject*> promise,
72 : HandleValue resolutionValue);
73 : static MOZ_MUST_USE bool reject(JSContext* cx, Handle<PromiseObject*> promise,
74 : HandleValue rejectionValue);
75 :
76 : static void onSettled(JSContext* cx, Handle<PromiseObject*> promise);
77 :
78 0 : double allocationTime() { return getFixedSlot(PromiseSlot_AllocationTime).toNumber(); }
79 0 : double resolutionTime() { return getFixedSlot(PromiseSlot_ResolutionTime).toNumber(); }
80 339 : JSObject* allocationSite() {
81 339 : return getFixedSlot(PromiseSlot_AllocationSite).toObjectOrNull();
82 : }
83 0 : JSObject* resolutionSite() {
84 0 : return getFixedSlot(PromiseSlot_ResolutionSite).toObjectOrNull();
85 : }
86 : double lifetime();
87 0 : double timeToResolution() {
88 0 : MOZ_ASSERT(state() != JS::PromiseState::Pending);
89 0 : return resolutionTime() - allocationTime();
90 : }
91 : MOZ_MUST_USE bool dependentPromises(JSContext* cx, MutableHandle<GCVector<Value>> values);
92 : uint64_t getID();
93 4 : bool isUnhandled() {
94 4 : MOZ_ASSERT(state() == JS::PromiseState::Rejected);
95 4 : return !(getFixedSlot(PromiseSlot_Flags).toInt32() & PROMISE_FLAG_HANDLED);
96 : }
97 : void markAsReported() {
98 : MOZ_ASSERT(isUnhandled());
99 : int32_t flags = getFixedSlot(PromiseSlot_Flags).toInt32();
100 : setFixedSlot(PromiseSlot_Flags, Int32Value(flags | PROMISE_FLAG_REPORTED));
101 : }
102 : };
103 :
104 : /**
105 : * Unforgeable version of the JS builtin Promise.all.
106 : *
107 : * Takes an AutoObjectVector of Promise objects and returns a promise that's
108 : * resolved with an array of resolution values when all those promises have
109 : * been resolved, or rejected with the rejection value of the first rejected
110 : * promise.
111 : *
112 : * Asserts that all objects in the `promises` vector are, maybe wrapped,
113 : * instances of `Promise` or a subclass of `Promise`.
114 : */
115 : MOZ_MUST_USE JSObject*
116 : GetWaitForAllPromise(JSContext* cx, const JS::AutoObjectVector& promises);
117 :
118 : /**
119 : * Enqueues resolve/reject reactions in the given Promise's reactions lists
120 : * as though calling the original value of Promise.prototype.then.
121 : *
122 : * If the `createDependent` flag is not set, no dependent Promise will be
123 : * created. This is used internally to implement DOM functionality.
124 : * Note: In this case, the reactions pushed using this function contain a
125 : * `promise` field that can contain null. That field is only ever used by
126 : * devtools, which have to treat these reactions specially.
127 : */
128 : MOZ_MUST_USE bool
129 : OriginalPromiseThen(JSContext* cx, Handle<PromiseObject*> promise,
130 : HandleValue onFulfilled, HandleValue onRejected,
131 : MutableHandleObject dependent, bool createDependent);
132 :
133 :
134 : MOZ_MUST_USE PromiseObject*
135 : CreatePromiseObjectForAsync(JSContext* cx, HandleValue generatorVal);
136 :
137 : MOZ_MUST_USE bool
138 : AsyncFunctionReturned(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value);
139 :
140 : MOZ_MUST_USE bool
141 : AsyncFunctionThrown(JSContext* cx, Handle<PromiseObject*> resultPromise);
142 :
143 : MOZ_MUST_USE bool
144 : AsyncFunctionAwait(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value);
145 :
146 : class AsyncGeneratorObject;
147 :
148 : MOZ_MUST_USE bool
149 : AsyncGeneratorAwait(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj, HandleValue value);
150 :
151 : MOZ_MUST_USE bool
152 : AsyncGeneratorResolve(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
153 : HandleValue value, bool done);
154 :
155 : MOZ_MUST_USE bool
156 : AsyncGeneratorReject(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
157 : HandleValue exception);
158 :
159 : MOZ_MUST_USE bool
160 : AsyncGeneratorEnqueue(JSContext* cx, HandleValue asyncGenVal, CompletionKind completionKind,
161 : HandleValue completionValue, MutableHandleValue result);
162 :
163 : bool
164 : AsyncFromSyncIteratorMethod(JSContext* cx, CallArgs& args, CompletionKind completionKind);
165 :
166 : /**
167 : * A PromiseTask represents a task that can be dispatched to a helper thread
168 : * (via StartPromiseTask), executed (by implementing PromiseTask::execute()),
169 : * and then resolved back on the original JSContext owner thread.
170 : * Because it contains a PersistentRooted, a PromiseTask will only be destroyed
171 : * on the JSContext's owner thread.
172 : */
173 : class PromiseTask : public JS::AsyncTask
174 : {
175 : JSRuntime* runtime_;
176 : PersistentRooted<PromiseObject*> promise_;
177 :
178 : // PromiseTask implements JS::AsyncTask and prevents derived classes from
179 : // overriding; derived classes should implement the new pure virtual
180 : // functions introduced below. Both of these methods 'delete this'.
181 : void finish(JSContext* cx) override final;
182 : void cancel(JSContext* cx) override final;
183 :
184 : protected:
185 : // Called by PromiseTask on the JSContext's owner thread after execute()
186 : // completes on the helper thread, assuming JS::FinishAsyncTaskCallback
187 : // succeeds. After this method returns, the task will be deleted.
188 : virtual bool finishPromise(JSContext* cx, Handle<PromiseObject*> promise) = 0;
189 :
190 : public:
191 : PromiseTask(JSContext* cx, Handle<PromiseObject*> promise);
192 : ~PromiseTask();
193 0 : JSRuntime* runtime() const { return runtime_; }
194 :
195 : // Called on a helper thread after StartAsyncTask. After execute()
196 : // completes, the JS::FinishAsyncTaskCallback will be called. If this fails
197 : // the task will be enqueued for deletion at some future point without ever
198 : // calling finishPromise().
199 : virtual void execute() = 0;
200 :
201 : // May be called in the absence of helper threads to synchronously execute
202 : // and finish a PromiseTask.
203 : bool executeAndFinish(JSContext* cx);
204 : };
205 :
206 : bool
207 : Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp);
208 : bool
209 : Promise_reject(JSContext* cx, unsigned argc, Value* vp);
210 : bool
211 : Promise_then(JSContext* cx, unsigned argc, Value* vp);
212 :
213 : } // namespace js
214 :
215 : #endif /* builtin_Promise_h */
|