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 :
8 : #include "builtin/Promise.h"
9 :
10 : #include "mozilla/Atomics.h"
11 : #include "mozilla/TimeStamp.h"
12 :
13 : #include "jscntxt.h"
14 : #include "jsexn.h"
15 : #include "jsfriendapi.h"
16 : #include "jsiter.h"
17 :
18 : #include "gc/Heap.h"
19 : #include "js/Debug.h"
20 : #include "vm/AsyncFunction.h"
21 : #include "vm/AsyncIteration.h"
22 :
23 : #include "jsobjinlines.h"
24 :
25 : #include "vm/NativeObject-inl.h"
26 :
27 : using namespace js;
28 :
29 : static double
30 736 : MillisecondsSinceStartup()
31 : {
32 736 : auto now = mozilla::TimeStamp::Now();
33 736 : return (now - mozilla::TimeStamp::ProcessCreation()).ToMilliseconds();
34 : }
35 :
36 : enum PromiseHandler {
37 : PromiseHandlerIdentity = 0,
38 : PromiseHandlerThrower,
39 : PromiseHandlerAsyncFunctionAwaitFulfilled,
40 : PromiseHandlerAsyncFunctionAwaitRejected,
41 : PromiseHandlerAsyncGeneratorAwaitFulfilled,
42 : PromiseHandlerAsyncGeneratorAwaitRejected,
43 :
44 : // Async Iteration proposal 6.1.1.2.1.
45 : // Async iterator handlers take the resolved value and create new iterator
46 : // objects. To do so it needs to forward whether the iterator is done. In
47 : // spec, this is achieved via the [[Done]] internal slot. We enumerate both
48 : // true and false cases here.
49 : PromiseHandlerAsyncIteratorValueUnwrapDone,
50 : PromiseHandlerAsyncIteratorValueUnwrapNotDone,
51 : };
52 :
53 : enum ResolutionMode {
54 : ResolveMode,
55 : RejectMode
56 : };
57 :
58 : enum ResolveFunctionSlots {
59 : ResolveFunctionSlot_Promise = 0,
60 : ResolveFunctionSlot_RejectFunction,
61 : };
62 :
63 : enum RejectFunctionSlots {
64 : RejectFunctionSlot_Promise = 0,
65 : RejectFunctionSlot_ResolveFunction,
66 : };
67 :
68 : enum PromiseAllResolveElementFunctionSlots {
69 : PromiseAllResolveElementFunctionSlot_Data = 0,
70 : PromiseAllResolveElementFunctionSlot_ElementIndex,
71 : };
72 :
73 : enum ReactionJobSlots {
74 : ReactionJobSlot_ReactionRecord = 0,
75 : };
76 :
77 : enum ThenableJobSlots {
78 : ThenableJobSlot_Handler = 0,
79 : ThenableJobSlot_JobData,
80 : };
81 :
82 : enum ThenableJobDataIndices {
83 : ThenableJobDataIndex_Promise = 0,
84 : ThenableJobDataIndex_Thenable,
85 : ThenableJobDataLength,
86 : };
87 :
88 : enum PromiseAllDataHolderSlots {
89 : PromiseAllDataHolderSlot_Promise = 0,
90 : PromiseAllDataHolderSlot_RemainingElements,
91 : PromiseAllDataHolderSlot_ValuesArray,
92 : PromiseAllDataHolderSlot_ResolveFunction,
93 : PromiseAllDataHolderSlots,
94 : };
95 :
96 : class PromiseAllDataHolder : public NativeObject
97 : {
98 : public:
99 : static const Class class_;
100 1 : JSObject* promiseObj() { return &getFixedSlot(PromiseAllDataHolderSlot_Promise).toObject(); }
101 1 : JSObject* resolveObj() {
102 1 : return &getFixedSlot(PromiseAllDataHolderSlot_ResolveFunction).toObject();
103 : }
104 5 : Value valuesArray() { return getFixedSlot(PromiseAllDataHolderSlot_ValuesArray); }
105 : int32_t remainingCount() {
106 : return getFixedSlot(PromiseAllDataHolderSlot_RemainingElements).toInt32();
107 : }
108 8 : int32_t increaseRemainingCount() {
109 8 : int32_t remainingCount = getFixedSlot(PromiseAllDataHolderSlot_RemainingElements).toInt32();
110 8 : remainingCount++;
111 8 : setFixedSlot(PromiseAllDataHolderSlot_RemainingElements, Int32Value(remainingCount));
112 8 : return remainingCount;
113 : }
114 8 : int32_t decreaseRemainingCount() {
115 8 : int32_t remainingCount = getFixedSlot(PromiseAllDataHolderSlot_RemainingElements).toInt32();
116 8 : remainingCount--;
117 8 : setFixedSlot(PromiseAllDataHolderSlot_RemainingElements, Int32Value(remainingCount));
118 8 : return remainingCount;
119 : }
120 : };
121 :
122 : const Class PromiseAllDataHolder::class_ = {
123 : "PromiseAllDataHolder",
124 : JSCLASS_HAS_RESERVED_SLOTS(PromiseAllDataHolderSlots)
125 : };
126 :
127 : static PromiseAllDataHolder*
128 3 : NewPromiseAllDataHolder(JSContext* cx, HandleObject resultPromise, HandleValue valuesArray,
129 : HandleObject resolve)
130 : {
131 6 : Rooted<PromiseAllDataHolder*> dataHolder(cx, NewObjectWithClassProto<PromiseAllDataHolder>(cx));
132 3 : if (!dataHolder)
133 0 : return nullptr;
134 :
135 3 : assertSameCompartment(cx, resultPromise);
136 3 : assertSameCompartment(cx, valuesArray);
137 3 : assertSameCompartment(cx, resolve);
138 :
139 3 : dataHolder->setFixedSlot(PromiseAllDataHolderSlot_Promise, ObjectValue(*resultPromise));
140 3 : dataHolder->setFixedSlot(PromiseAllDataHolderSlot_RemainingElements, Int32Value(1));
141 3 : dataHolder->setFixedSlot(PromiseAllDataHolderSlot_ValuesArray, valuesArray);
142 3 : dataHolder->setFixedSlot(PromiseAllDataHolderSlot_ResolveFunction, ObjectValue(*resolve));
143 3 : return dataHolder;
144 : }
145 :
146 : /**
147 : * Wrapper for GetAndClearException that handles cases where no exception is
148 : * pending, but an error occurred. This can be the case if an OOM was
149 : * encountered while throwing the error.
150 : */
151 : static bool
152 0 : MaybeGetAndClearException(JSContext* cx, MutableHandleValue rval)
153 : {
154 0 : if (!cx->isExceptionPending())
155 0 : return false;
156 :
157 0 : return GetAndClearException(cx, rval);
158 : }
159 :
160 : static MOZ_MUST_USE bool RunResolutionFunction(JSContext *cx, HandleObject resolutionFun,
161 : HandleValue result, ResolutionMode mode,
162 : HandleObject promiseObj);
163 :
164 : // ES2016, 25.4.1.1.1, Steps 1.a-b.
165 : // Extracting all of this internal spec algorithm into a helper function would
166 : // be tedious, so the check in step 1 and the entirety of step 2 aren't
167 : // included.
168 : static bool
169 0 : AbruptRejectPromise(JSContext *cx, CallArgs& args, HandleObject promiseObj, HandleObject reject)
170 : {
171 : // Step 1.a.
172 0 : RootedValue reason(cx);
173 0 : if (!MaybeGetAndClearException(cx, &reason))
174 0 : return false;
175 :
176 0 : if (!RunResolutionFunction(cx, reject, reason, RejectMode, promiseObj))
177 0 : return false;
178 :
179 : // Step 1.b.
180 0 : args.rval().setObject(*promiseObj);
181 0 : return true;
182 : }
183 :
184 : enum ReactionRecordSlots {
185 : ReactionRecordSlot_Promise = 0,
186 : ReactionRecordSlot_OnFulfilled,
187 : ReactionRecordSlot_OnRejected,
188 : ReactionRecordSlot_Resolve,
189 : ReactionRecordSlot_Reject,
190 : ReactionRecordSlot_IncumbentGlobalObject,
191 : ReactionRecordSlot_Flags,
192 : ReactionRecordSlot_HandlerArg,
193 : ReactionRecordSlot_Generator,
194 : ReactionRecordSlots,
195 : };
196 :
197 : #define REACTION_FLAG_RESOLVED 0x1
198 : #define REACTION_FLAG_FULFILLED 0x2
199 : #define REACTION_FLAG_IGNORE_DEFAULT_RESOLUTION 0x4
200 : #define REACTION_FLAG_ASYNC_FUNCTION_AWAIT 0x8
201 : #define REACTION_FLAG_ASYNC_GENERATOR_AWAIT 0x10
202 :
203 : // ES2016, 25.4.1.2.
204 : class PromiseReactionRecord : public NativeObject
205 : {
206 : public:
207 : static const Class class_;
208 :
209 308 : JSObject* promise() { return getFixedSlot(ReactionRecordSlot_Promise).toObjectOrNull(); }
210 1611 : int32_t flags() { return getFixedSlot(ReactionRecordSlot_Flags).toInt32(); }
211 1078 : JS::PromiseState targetState() {
212 1078 : int32_t flags = this->flags();
213 1078 : if (!(flags & REACTION_FLAG_RESOLVED))
214 308 : return JS::PromiseState::Pending;
215 770 : return flags & REACTION_FLAG_FULFILLED
216 770 : ? JS::PromiseState::Fulfilled
217 770 : : JS::PromiseState::Rejected;
218 : }
219 154 : void setTargetState(JS::PromiseState state) {
220 154 : int32_t flags = this->flags();
221 154 : MOZ_ASSERT(!(flags & REACTION_FLAG_RESOLVED));
222 154 : MOZ_ASSERT(state != JS::PromiseState::Pending, "Can't revert a reaction to pending.");
223 154 : flags |= REACTION_FLAG_RESOLVED;
224 154 : if (state == JS::PromiseState::Fulfilled)
225 149 : flags |= REACTION_FLAG_FULFILLED;
226 154 : setFixedSlot(ReactionRecordSlot_Flags, Int32Value(flags));
227 154 : }
228 71 : void setIsAsyncFunctionAwait() {
229 71 : int32_t flags = this->flags();
230 71 : flags |= REACTION_FLAG_ASYNC_FUNCTION_AWAIT;
231 71 : setFixedSlot(ReactionRecordSlot_Flags, Int32Value(flags));
232 71 : }
233 206 : bool isAsyncFunctionAwait() {
234 206 : int32_t flags = this->flags();
235 206 : return flags & REACTION_FLAG_ASYNC_FUNCTION_AWAIT;
236 : }
237 0 : void setIsAsyncGeneratorAwait(Handle<AsyncGeneratorObject*> asyncGenObj) {
238 0 : int32_t flags = this->flags();
239 0 : flags |= REACTION_FLAG_ASYNC_GENERATOR_AWAIT;
240 0 : setFixedSlot(ReactionRecordSlot_Flags, Int32Value(flags));
241 :
242 0 : setFixedSlot(ReactionRecordSlot_Generator, ObjectValue(*asyncGenObj));
243 0 : }
244 102 : bool isAsyncGeneratorAwait() {
245 102 : int32_t flags = this->flags();
246 102 : return flags & REACTION_FLAG_ASYNC_GENERATOR_AWAIT;
247 : }
248 0 : AsyncGeneratorObject* asyncGenerator() {
249 0 : MOZ_ASSERT(isAsyncGeneratorAwait());
250 0 : return &getFixedSlot(ReactionRecordSlot_Generator).toObject()
251 0 : .as<AsyncGeneratorObject>();
252 : }
253 308 : Value handler() {
254 308 : MOZ_ASSERT(targetState() != JS::PromiseState::Pending);
255 308 : uint32_t slot = targetState() == JS::PromiseState::Fulfilled
256 308 : ? ReactionRecordSlot_OnFulfilled
257 308 : : ReactionRecordSlot_OnRejected;
258 308 : return getFixedSlot(slot);
259 : }
260 154 : Value handlerArg() {
261 154 : MOZ_ASSERT(targetState() != JS::PromiseState::Pending);
262 154 : return getFixedSlot(ReactionRecordSlot_HandlerArg);
263 : }
264 154 : void setHandlerArg(Value& arg) {
265 154 : MOZ_ASSERT(targetState() == JS::PromiseState::Pending);
266 154 : setFixedSlot(ReactionRecordSlot_HandlerArg, arg);
267 154 : }
268 154 : JSObject* incumbentGlobalObject() {
269 154 : return getFixedSlot(ReactionRecordSlot_IncumbentGlobalObject).toObjectOrNull();
270 : }
271 : };
272 :
273 : const Class PromiseReactionRecord::class_ = {
274 : "PromiseReactionRecord",
275 : JSCLASS_HAS_RESERVED_SLOTS(ReactionRecordSlots)
276 : };
277 :
278 : static void
279 461 : AddPromiseFlags(PromiseObject& promise, int32_t flag)
280 : {
281 461 : int32_t flags = promise.getFixedSlot(PromiseSlot_Flags).toInt32();
282 461 : promise.setFixedSlot(PromiseSlot_Flags, Int32Value(flags | flag));
283 461 : }
284 :
285 : static bool
286 122 : PromiseHasAnyFlag(PromiseObject& promise, int32_t flag)
287 : {
288 122 : return promise.getFixedSlot(PromiseSlot_Flags).toInt32() & flag;
289 : }
290 :
291 : static bool ResolvePromiseFunction(JSContext* cx, unsigned argc, Value* vp);
292 : static bool RejectPromiseFunction(JSContext* cx, unsigned argc, Value* vp);
293 :
294 : // ES2016, 25.4.1.3.
295 : static MOZ_MUST_USE bool
296 177 : CreateResolvingFunctions(JSContext* cx, HandleValue promise,
297 : MutableHandleValue resolveVal,
298 : MutableHandleValue rejectVal)
299 : {
300 354 : RootedAtom funName(cx, cx->names().empty);
301 354 : RootedFunction resolve(cx, NewNativeFunction(cx, ResolvePromiseFunction, 1, funName,
302 354 : gc::AllocKind::FUNCTION_EXTENDED, GenericObject));
303 177 : if (!resolve)
304 0 : return false;
305 :
306 354 : RootedFunction reject(cx, NewNativeFunction(cx, RejectPromiseFunction, 1, funName,
307 354 : gc::AllocKind::FUNCTION_EXTENDED, GenericObject));
308 177 : if (!reject)
309 0 : return false;
310 :
311 177 : resolve->setExtendedSlot(ResolveFunctionSlot_Promise, promise);
312 177 : resolve->setExtendedSlot(ResolveFunctionSlot_RejectFunction, ObjectValue(*reject));
313 :
314 177 : reject->setExtendedSlot(RejectFunctionSlot_Promise, promise);
315 177 : reject->setExtendedSlot(RejectFunctionSlot_ResolveFunction, ObjectValue(*resolve));
316 :
317 177 : resolveVal.setObject(*resolve);
318 177 : rejectVal.setObject(*reject);
319 :
320 177 : return true;
321 : }
322 :
323 : static void ClearResolutionFunctionSlots(JSFunction* resolutionFun);
324 : static MOZ_MUST_USE bool RejectMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj,
325 : HandleValue reason);
326 :
327 : // ES2016, 25.4.1.3.1.
328 : static bool
329 3 : RejectPromiseFunction(JSContext* cx, unsigned argc, Value* vp)
330 : {
331 3 : CallArgs args = CallArgsFromVp(argc, vp);
332 :
333 6 : RootedFunction reject(cx, &args.callee().as<JSFunction>());
334 6 : RootedValue reasonVal(cx, args.get(0));
335 :
336 : // Steps 1-2.
337 6 : RootedValue promiseVal(cx, reject->getExtendedSlot(RejectFunctionSlot_Promise));
338 :
339 : // Steps 3-4.
340 : // If the Promise isn't available anymore, it has been resolved and the
341 : // reference to it removed to make it eligible for collection.
342 3 : if (promiseVal.isUndefined()) {
343 0 : args.rval().setUndefined();
344 0 : return true;
345 : }
346 :
347 : // Step 5.
348 : // Here, we only remove the Promise reference from the resolution
349 : // functions. Actually marking it as fulfilled/rejected happens later.
350 3 : ClearResolutionFunctionSlots(reject);
351 :
352 6 : RootedObject promise(cx, &promiseVal.toObject());
353 :
354 : // In some cases the Promise reference on the resolution function won't
355 : // have been removed during resolution, so we need to check that here,
356 : // too.
357 4 : if (promise->is<PromiseObject>() &&
358 1 : promise->as<PromiseObject>().state() != JS::PromiseState::Pending)
359 : {
360 0 : return true;
361 : }
362 :
363 : // Step 6.
364 3 : if (!RejectMaybeWrappedPromise(cx, promise, reasonVal))
365 0 : return false;
366 3 : args.rval().setUndefined();
367 3 : return true;
368 : }
369 :
370 : static MOZ_MUST_USE bool FulfillMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj,
371 : HandleValue value_);
372 :
373 : static MOZ_MUST_USE bool EnqueuePromiseResolveThenableJob(JSContext* cx,
374 : HandleValue promiseToResolve,
375 : HandleValue thenable,
376 : HandleValue thenVal);
377 :
378 : // ES2016, 25.4.1.3.2, steps 6-13.
379 : static MOZ_MUST_USE bool
380 308 : ResolvePromiseInternal(JSContext* cx, HandleObject promise, HandleValue resolutionVal)
381 : {
382 : // Step 7 (reordered).
383 308 : if (!resolutionVal.isObject())
384 134 : return FulfillMaybeWrappedPromise(cx, promise, resolutionVal);
385 :
386 348 : RootedObject resolution(cx, &resolutionVal.toObject());
387 :
388 : // Step 6.
389 174 : if (resolution == promise) {
390 : // Step 6.a.
391 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
392 0 : JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF);
393 0 : RootedValue selfResolutionError(cx);
394 0 : if (!MaybeGetAndClearException(cx, &selfResolutionError))
395 0 : return false;
396 :
397 : // Step 6.b.
398 0 : return RejectMaybeWrappedPromise(cx, promise, selfResolutionError);
399 : }
400 :
401 : // Step 8.
402 348 : RootedValue thenVal(cx);
403 174 : bool status = GetProperty(cx, resolution, resolution, cx->names().then, &thenVal);
404 :
405 : // Step 9.
406 174 : if (!status) {
407 0 : RootedValue error(cx);
408 0 : if (!MaybeGetAndClearException(cx, &error))
409 0 : return false;
410 :
411 0 : return RejectMaybeWrappedPromise(cx, promise, error);
412 : }
413 :
414 : // Step 10 (implicit).
415 :
416 : // Step 11.
417 174 : if (!IsCallable(thenVal))
418 93 : return FulfillMaybeWrappedPromise(cx, promise, resolutionVal);
419 :
420 : // Step 12.
421 162 : RootedValue promiseVal(cx, ObjectValue(*promise));
422 81 : if (!EnqueuePromiseResolveThenableJob(cx, promiseVal, resolutionVal, thenVal))
423 0 : return false;
424 :
425 : // Step 13.
426 81 : return true;
427 : }
428 :
429 : // ES2016, 25.4.1.3.2.
430 : static bool
431 89 : ResolvePromiseFunction(JSContext* cx, unsigned argc, Value* vp)
432 : {
433 89 : CallArgs args = CallArgsFromVp(argc, vp);
434 :
435 178 : RootedFunction resolve(cx, &args.callee().as<JSFunction>());
436 178 : RootedValue resolutionVal(cx, args.get(0));
437 :
438 : // Steps 3-4 (reordered).
439 : // We use the reference to the reject function as a signal for whether
440 : // the resolve or reject function was already called, at which point
441 : // the references on each of the functions are cleared.
442 89 : if (!resolve->getExtendedSlot(ResolveFunctionSlot_RejectFunction).isObject()) {
443 0 : args.rval().setUndefined();
444 0 : return true;
445 : }
446 :
447 : // Steps 1-2 (reordered).
448 178 : RootedObject promise(cx, &resolve->getExtendedSlot(ResolveFunctionSlot_Promise).toObject());
449 :
450 : // Step 5.
451 : // Here, we only remove the Promise reference from the resolution
452 : // functions. Actually marking it as fulfilled/rejected happens later.
453 89 : ClearResolutionFunctionSlots(resolve);
454 :
455 : // In some cases the Promise reference on the resolution function won't
456 : // have been removed during resolution, so we need to check that here,
457 : // too.
458 152 : if (promise->is<PromiseObject>() &&
459 63 : promise->as<PromiseObject>().state() != JS::PromiseState::Pending)
460 : {
461 0 : return true;
462 : }
463 :
464 : // Steps 6-13.
465 89 : if (!ResolvePromiseInternal(cx, promise, resolutionVal))
466 0 : return false;
467 89 : args.rval().setUndefined();
468 89 : return true;
469 : }
470 :
471 : static bool PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp);
472 :
473 : /**
474 : * Tells the embedding to enqueue a Promise reaction job, based on
475 : * three parameters:
476 : * reactionObj - The reaction record.
477 : * handlerArg_ - The first and only argument to pass to the handler invoked by
478 : * the job. This will be stored on the reaction record.
479 : * targetState - The PromiseState this reaction job targets. This decides
480 : * whether the onFulfilled or onRejected handler is called.
481 : */
482 : MOZ_MUST_USE static bool
483 154 : EnqueuePromiseReactionJob(JSContext* cx, HandleObject reactionObj,
484 : HandleValue handlerArg_, JS::PromiseState targetState)
485 : {
486 : // The reaction might have been stored on a Promise from another
487 : // compartment, which means it would've been wrapped in a CCW.
488 : // To properly handle that case here, unwrap it and enter its
489 : // compartment, where the job creation should take place anyway.
490 308 : Rooted<PromiseReactionRecord*> reaction(cx);
491 308 : RootedValue handlerArg(cx, handlerArg_);
492 308 : mozilla::Maybe<AutoCompartment> ac;
493 154 : if (!IsProxy(reactionObj)) {
494 154 : MOZ_RELEASE_ASSERT(reactionObj->is<PromiseReactionRecord>());
495 154 : reaction = &reactionObj->as<PromiseReactionRecord>();
496 : } else {
497 0 : if (JS_IsDeadWrapper(UncheckedUnwrap(reactionObj))) {
498 0 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
499 0 : return false;
500 : }
501 0 : reaction = &UncheckedUnwrap(reactionObj)->as<PromiseReactionRecord>();
502 0 : MOZ_RELEASE_ASSERT(reaction->is<PromiseReactionRecord>());
503 0 : ac.emplace(cx, reaction);
504 0 : if (!reaction->compartment()->wrap(cx, &handlerArg))
505 0 : return false;
506 : }
507 :
508 : // Must not enqueue a reaction job more than once.
509 154 : MOZ_ASSERT(reaction->targetState() == JS::PromiseState::Pending);
510 :
511 154 : assertSameCompartment(cx, handlerArg);
512 154 : reaction->setHandlerArg(handlerArg.get());
513 :
514 308 : RootedValue reactionVal(cx, ObjectValue(*reaction));
515 :
516 154 : reaction->setTargetState(targetState);
517 308 : RootedValue handler(cx, reaction->handler());
518 :
519 : // If we have a handler callback, we enter that handler's compartment so
520 : // that the promise reaction job function is created in that compartment.
521 : // That guarantees that the embedding ends up with the right entry global.
522 : // This is relevant for some html APIs like fetch that derive information
523 : // from said global.
524 308 : mozilla::Maybe<AutoCompartment> ac2;
525 154 : if (handler.isObject()) {
526 174 : RootedObject handlerObj(cx, &handler.toObject());
527 :
528 : // The unwrapping has to be unchecked because we specifically want to
529 : // be able to use handlers with wrappers that would only allow calls.
530 : // E.g., it's ok to have a handler from a chrome compartment in a
531 : // reaction to a content compartment's Promise instance.
532 87 : handlerObj = UncheckedUnwrap(handlerObj);
533 87 : MOZ_ASSERT(handlerObj);
534 87 : ac2.emplace(cx, handlerObj);
535 :
536 : // We need to wrap the reaction to store it on the job function.
537 87 : if (!cx->compartment()->wrap(cx, &reactionVal))
538 0 : return false;
539 : }
540 :
541 : // Create the JS function to call when the job is triggered.
542 308 : RootedAtom funName(cx, cx->names().empty);
543 308 : RootedFunction job(cx, NewNativeFunction(cx, PromiseReactionJob, 0, funName,
544 308 : gc::AllocKind::FUNCTION_EXTENDED, GenericObject));
545 154 : if (!job)
546 0 : return false;
547 :
548 : // Store the reaction on the reaction job.
549 154 : job->setExtendedSlot(ReactionJobSlot_ReactionRecord, reactionVal);
550 :
551 : // When using JS::AddPromiseReactions, no actual promise is created, so we
552 : // might not have one here.
553 : // Additionally, we might have an object here that isn't an instance of
554 : // Promise. This can happen if content overrides the value of
555 : // Promise[@@species] (or invokes Promise#then on a Promise subclass
556 : // instance with a non-default @@species value on the constructor) with a
557 : // function that returns objects that're not Promise (subclass) instances.
558 : // In that case, we just pretend we didn't have an object in the first
559 : // place.
560 : // If after all this we do have an object, wrap it in case we entered the
561 : // handler's compartment above, because we should pass objects from a
562 : // single compartment to the enqueuePromiseJob callback.
563 308 : RootedObject promise(cx, reaction->promise());
564 154 : if (promise && promise->is<PromiseObject>()) {
565 154 : if (!cx->compartment()->wrap(cx, &promise))
566 0 : return false;
567 : }
568 :
569 : // Using objectFromIncumbentGlobal, we can derive the incumbent global by
570 : // unwrapping and then getting the global. This is very convoluted, but
571 : // much better than having to store the original global as a private value
572 : // because we couldn't wrap it to store it as a normal JS value.
573 308 : RootedObject global(cx);
574 308 : RootedObject objectFromIncumbentGlobal(cx, reaction->incumbentGlobalObject());
575 154 : if (objectFromIncumbentGlobal) {
576 154 : objectFromIncumbentGlobal = CheckedUnwrap(objectFromIncumbentGlobal);
577 154 : MOZ_ASSERT(objectFromIncumbentGlobal);
578 154 : global = &objectFromIncumbentGlobal->global();
579 : }
580 :
581 : // Note: the global we pass here might be from a different compartment
582 : // than job and promise. While it's somewhat unusual to pass objects
583 : // from multiple compartments, in this case we specifically need the
584 : // global to be unwrapped because wrapping and unwrapping aren't
585 : // necessarily symmetric for globals.
586 154 : return cx->runtime()->enqueuePromiseJob(cx, job, promise, global);
587 : }
588 :
589 : static MOZ_MUST_USE bool TriggerPromiseReactions(JSContext* cx, HandleValue reactionsVal,
590 : JS::PromiseState state, HandleValue valueOrReason);
591 :
592 : // ES2016, Commoned-out implementation of 25.4.1.4. and 25.4.1.7.
593 : static MOZ_MUST_USE bool
594 231 : ResolvePromise(JSContext* cx, Handle<PromiseObject*> promise, HandleValue valueOrReason,
595 : JS::PromiseState state)
596 : {
597 : // Step 1.
598 231 : MOZ_ASSERT(promise->state() == JS::PromiseState::Pending);
599 231 : MOZ_ASSERT(state == JS::PromiseState::Fulfilled || state == JS::PromiseState::Rejected);
600 :
601 : // Step 2.
602 : // We only have one list of reactions for both resolution types. So
603 : // instead of getting the right list of reactions, we determine the
604 : // resolution type to retrieve the right information from the
605 : // reaction records.
606 462 : RootedValue reactionsVal(cx, promise->getFixedSlot(PromiseSlot_ReactionsOrResult));
607 :
608 : // Steps 3-5.
609 : // The same slot is used for the reactions list and the result, so setting
610 : // the result also removes the reactions list.
611 231 : promise->setFixedSlot(PromiseSlot_ReactionsOrResult, valueOrReason);
612 :
613 : // Step 6.
614 231 : int32_t flags = promise->getFixedSlot(PromiseSlot_Flags).toInt32();
615 231 : flags |= PROMISE_FLAG_RESOLVED;
616 231 : if (state == JS::PromiseState::Fulfilled)
617 227 : flags |= PROMISE_FLAG_FULFILLED;
618 231 : promise->setFixedSlot(PromiseSlot_Flags, Int32Value(flags));
619 :
620 : // Also null out the resolve/reject functions so they can be GC'd.
621 231 : promise->setFixedSlot(PromiseSlot_RejectFunction, UndefinedValue());
622 :
623 : // Now that everything else is done, do the things the debugger needs.
624 : // Step 7 of RejectPromise implemented in onSettled.
625 231 : PromiseObject::onSettled(cx, promise);
626 :
627 : // Step 7 of FulfillPromise.
628 : // Step 8 of RejectPromise.
629 231 : if (reactionsVal.isObject())
630 117 : return TriggerPromiseReactions(cx, reactionsVal, state, valueOrReason);
631 :
632 114 : return true;
633 : }
634 :
635 : // ES2016, 25.4.1.4.
636 : static MOZ_MUST_USE bool
637 227 : FulfillMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj, HandleValue value_)
638 : {
639 454 : Rooted<PromiseObject*> promise(cx);
640 454 : RootedValue value(cx, value_);
641 :
642 454 : mozilla::Maybe<AutoCompartment> ac;
643 227 : if (!IsProxy(promiseObj)) {
644 201 : promise = &promiseObj->as<PromiseObject>();
645 : } else {
646 26 : if (JS_IsDeadWrapper(UncheckedUnwrap(promiseObj))) {
647 0 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
648 0 : return false;
649 : }
650 26 : promise = &UncheckedUnwrap(promiseObj)->as<PromiseObject>();
651 26 : ac.emplace(cx, promise);
652 26 : if (!promise->compartment()->wrap(cx, &value))
653 0 : return false;
654 : }
655 :
656 227 : MOZ_ASSERT(promise->state() == JS::PromiseState::Pending);
657 :
658 227 : return ResolvePromise(cx, promise, value, JS::PromiseState::Fulfilled);
659 : }
660 :
661 : static bool GetCapabilitiesExecutor(JSContext* cx, unsigned argc, Value* vp);
662 : static bool PromiseConstructor(JSContext* cx, unsigned argc, Value* vp);
663 : static MOZ_MUST_USE PromiseObject* CreatePromiseObjectInternal(JSContext* cx,
664 : HandleObject proto = nullptr,
665 : bool protoIsWrapped = false,
666 : bool informDebugger = true);
667 :
668 : enum GetCapabilitiesExecutorSlots {
669 : GetCapabilitiesExecutorSlots_Resolve,
670 : GetCapabilitiesExecutorSlots_Reject
671 : };
672 :
673 : static MOZ_MUST_USE PromiseObject*
674 409 : CreatePromiseObjectWithoutResolutionFunctions(JSContext* cx)
675 : {
676 818 : Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx));
677 409 : if (!promise)
678 0 : return nullptr;
679 :
680 409 : AddPromiseFlags(*promise, PROMISE_FLAG_DEFAULT_RESOLVE_FUNCTION |
681 409 : PROMISE_FLAG_DEFAULT_REJECT_FUNCTION);
682 409 : return promise;
683 : }
684 :
685 : // ES2016, 25.4.1.5.
686 : static MOZ_MUST_USE bool
687 287 : NewPromiseCapability(JSContext* cx, HandleObject C, MutableHandleObject promise,
688 : MutableHandleObject resolve, MutableHandleObject reject,
689 : bool canOmitResolutionFunctions)
690 : {
691 574 : RootedValue cVal(cx, ObjectValue(*C));
692 :
693 : // Steps 1-2.
694 287 : if (!IsConstructor(C)) {
695 0 : ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, -1, cVal, nullptr);
696 0 : return false;
697 : }
698 :
699 : // If we'd call the original Promise constructor and know that the
700 : // resolve/reject functions won't ever escape to content, we can skip
701 : // creating and calling the executor function and instead return a Promise
702 : // marked as having default resolve/reject functions.
703 : //
704 : // This can't be used in Promise.all and Promise.race because we have to
705 : // pass the reject (and resolve, in the race case) function to thenables
706 : // in the list passed to all/race, which (potentially) means exposing them
707 : // to content.
708 287 : if (canOmitResolutionFunctions && IsNativeFunction(cVal, PromiseConstructor)) {
709 284 : promise.set(CreatePromiseObjectWithoutResolutionFunctions(cx));
710 284 : if (!promise)
711 0 : return false;
712 284 : return true;
713 : }
714 :
715 : // Step 3 (omitted).
716 :
717 : // Step 4.
718 6 : RootedAtom funName(cx, cx->names().empty);
719 6 : RootedFunction executor(cx, NewNativeFunction(cx, GetCapabilitiesExecutor, 2, funName,
720 6 : gc::AllocKind::FUNCTION_EXTENDED, GenericObject));
721 3 : if (!executor)
722 0 : return false;
723 :
724 : // Step 5 (omitted).
725 :
726 : // Step 6.
727 6 : FixedConstructArgs<1> cargs(cx);
728 3 : cargs[0].setObject(*executor);
729 3 : if (!Construct(cx, cVal, cargs, cVal, promise))
730 0 : return false;
731 :
732 : // Step 7.
733 6 : RootedValue resolveVal(cx, executor->getExtendedSlot(GetCapabilitiesExecutorSlots_Resolve));
734 3 : if (!IsCallable(resolveVal)) {
735 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
736 0 : JSMSG_PROMISE_RESOLVE_FUNCTION_NOT_CALLABLE);
737 0 : return false;
738 : }
739 :
740 : // Step 8.
741 6 : RootedValue rejectVal(cx, executor->getExtendedSlot(GetCapabilitiesExecutorSlots_Reject));
742 3 : if (!IsCallable(rejectVal)) {
743 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
744 0 : JSMSG_PROMISE_REJECT_FUNCTION_NOT_CALLABLE);
745 0 : return false;
746 : }
747 :
748 : // Step 9 (well, the equivalent for all of promiseCapabilities' fields.)
749 3 : resolve.set(&resolveVal.toObject());
750 3 : reject.set(&rejectVal.toObject());
751 :
752 : // Step 10.
753 3 : return true;
754 : }
755 :
756 : // ES2016, 25.4.1.5.1.
757 : static bool
758 3 : GetCapabilitiesExecutor(JSContext* cx, unsigned argc, Value* vp)
759 : {
760 3 : CallArgs args = CallArgsFromVp(argc, vp);
761 6 : RootedFunction F(cx, &args.callee().as<JSFunction>());
762 :
763 : // Steps 1-2 (implicit).
764 :
765 : // Steps 3-4.
766 6 : if (!F->getExtendedSlot(GetCapabilitiesExecutorSlots_Resolve).isUndefined() ||
767 3 : !F->getExtendedSlot(GetCapabilitiesExecutorSlots_Reject).isUndefined())
768 : {
769 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
770 0 : JSMSG_PROMISE_CAPABILITY_HAS_SOMETHING_ALREADY);
771 0 : return false;
772 : }
773 :
774 : // Step 5.
775 3 : F->setExtendedSlot(GetCapabilitiesExecutorSlots_Resolve, args.get(0));
776 :
777 : // Step 6.
778 3 : F->setExtendedSlot(GetCapabilitiesExecutorSlots_Reject, args.get(1));
779 :
780 : // Step 7.
781 3 : args.rval().setUndefined();
782 3 : return true;
783 : }
784 :
785 : // ES2016, 25.4.1.7.
786 : static MOZ_MUST_USE bool
787 4 : RejectMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj, HandleValue reason_)
788 : {
789 8 : Rooted<PromiseObject*> promise(cx);
790 8 : RootedValue reason(cx, reason_);
791 :
792 8 : mozilla::Maybe<AutoCompartment> ac;
793 4 : if (!IsProxy(promiseObj)) {
794 2 : promise = &promiseObj->as<PromiseObject>();
795 : } else {
796 2 : if (JS_IsDeadWrapper(UncheckedUnwrap(promiseObj))) {
797 0 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
798 0 : return false;
799 : }
800 2 : promise = &UncheckedUnwrap(promiseObj)->as<PromiseObject>();
801 2 : ac.emplace(cx, promise);
802 :
803 : // The rejection reason might've been created in a compartment with higher
804 : // privileges than the Promise's. In that case, object-type rejection
805 : // values might be wrapped into a wrapper that throws whenever the
806 : // Promise's reaction handler wants to do anything useful with it. To
807 : // avoid that situation, we synthesize a generic error that doesn't
808 : // expose any privileged information but can safely be used in the
809 : // rejection handler.
810 2 : if (!promise->compartment()->wrap(cx, &reason))
811 0 : return false;
812 2 : if (reason.isObject() && !CheckedUnwrap(&reason.toObject())) {
813 : // Report the existing reason, so we don't just drop it on the
814 : // floor.
815 0 : RootedObject realReason(cx, UncheckedUnwrap(&reason.toObject()));
816 0 : RootedValue realReasonVal(cx, ObjectValue(*realReason));
817 0 : RootedObject realGlobal(cx, &realReason->global());
818 0 : ReportErrorToGlobal(cx, realGlobal, realReasonVal);
819 :
820 : // Async stacks are only properly adopted if there's at least one
821 : // interpreter frame active right now. If a thenable job with a
822 : // throwing `then` function got us here, that'll not be the case,
823 : // so we add one by throwing the error from self-hosted code.
824 0 : if (!GetInternalError(cx, JSMSG_PROMISE_ERROR_IN_WRAPPED_REJECTION_REASON, &reason))
825 0 : return false;
826 : }
827 : }
828 :
829 4 : MOZ_ASSERT(promise->state() == JS::PromiseState::Pending);
830 :
831 4 : return ResolvePromise(cx, promise, reason, JS::PromiseState::Rejected);
832 : }
833 :
834 : // ES2016, 25.4.1.8.
835 : static MOZ_MUST_USE bool
836 117 : TriggerPromiseReactions(JSContext* cx, HandleValue reactionsVal, JS::PromiseState state,
837 : HandleValue valueOrReason)
838 : {
839 234 : RootedObject reactions(cx, &reactionsVal.toObject());
840 234 : RootedObject reaction(cx);
841 :
842 117 : if (reactions->is<PromiseReactionRecord>() || IsWrapper(reactions))
843 111 : return EnqueuePromiseReactionJob(cx, reactions, valueOrReason, state);
844 :
845 12 : RootedNativeObject reactionsList(cx, &reactions->as<NativeObject>());
846 6 : size_t reactionsCount = reactionsList->getDenseInitializedLength();
847 6 : MOZ_ASSERT(reactionsCount > 1, "Reactions list should be created lazily");
848 :
849 12 : RootedValue reactionVal(cx);
850 18 : for (size_t i = 0; i < reactionsCount; i++) {
851 12 : reactionVal = reactionsList->getDenseElement(i);
852 12 : MOZ_RELEASE_ASSERT(reactionVal.isObject());
853 12 : reaction = &reactionVal.toObject();
854 12 : if (!EnqueuePromiseReactionJob(cx, reaction, valueOrReason, state))
855 0 : return false;
856 : }
857 :
858 6 : return true;
859 : }
860 :
861 : static MOZ_MUST_USE bool
862 52 : AsyncFunctionAwaitPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord*> reaction,
863 : MutableHandleValue rval)
864 : {
865 52 : MOZ_ASSERT(reaction->isAsyncFunctionAwait());
866 :
867 104 : RootedValue handlerVal(cx, reaction->handler());
868 104 : RootedValue argument(cx, reaction->handlerArg());
869 104 : Rooted<PromiseObject*> resultPromise(cx, &reaction->promise()->as<PromiseObject>());
870 104 : RootedValue generatorVal(cx, resultPromise->getFixedSlot(PromiseSlot_AwaitGenerator));
871 :
872 52 : int32_t handlerNum = int32_t(handlerVal.toNumber());
873 52 : MOZ_ASSERT(handlerNum == PromiseHandlerAsyncFunctionAwaitFulfilled ||
874 : handlerNum == PromiseHandlerAsyncFunctionAwaitRejected);
875 :
876 : // Await's handlers don't return a value, nor throw exception.
877 : // They fail only on OOM.
878 52 : if (handlerNum == PromiseHandlerAsyncFunctionAwaitFulfilled) {
879 51 : if (!AsyncFunctionAwaitedFulfilled(cx, resultPromise, generatorVal, argument))
880 0 : return false;
881 : } else {
882 1 : if (!AsyncFunctionAwaitedRejected(cx, resultPromise, generatorVal, argument))
883 0 : return false;
884 : }
885 :
886 52 : rval.setUndefined();
887 52 : return true;
888 : }
889 :
890 : static MOZ_MUST_USE bool
891 0 : AsyncGeneratorAwaitPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord*> reaction,
892 : MutableHandleValue rval)
893 : {
894 0 : MOZ_ASSERT(reaction->isAsyncGeneratorAwait());
895 :
896 0 : RootedValue handlerVal(cx, reaction->handler());
897 0 : RootedValue argument(cx, reaction->handlerArg());
898 0 : Rooted<AsyncGeneratorObject*> asyncGenObj(cx, reaction->asyncGenerator());
899 :
900 0 : int32_t handlerNum = int32_t(handlerVal.toNumber());
901 0 : MOZ_ASSERT(handlerNum == PromiseHandlerAsyncGeneratorAwaitFulfilled ||
902 : handlerNum == PromiseHandlerAsyncGeneratorAwaitRejected);
903 :
904 : // Await's handlers don't return a value, nor throw exception.
905 : // They fail only on OOM.
906 0 : if (handlerNum == PromiseHandlerAsyncGeneratorAwaitFulfilled) {
907 0 : if (!AsyncGeneratorAwaitedFulfilled(cx, asyncGenObj, argument))
908 0 : return false;
909 : } else {
910 0 : if (!AsyncGeneratorAwaitedRejected(cx, asyncGenObj, argument))
911 0 : return false;
912 : }
913 :
914 0 : rval.setUndefined();
915 0 : return true;
916 : }
917 :
918 : // ES2016, 25.4.2.1.
919 : /**
920 : * Callback triggering the fulfill/reject reaction for a resolved Promise,
921 : * to be invoked by the embedding during its processing of the Promise job
922 : * queue.
923 : *
924 : * See http://www.ecma-international.org/ecma-262/7.0/index.html#sec-jobs-and-job-queues
925 : *
926 : * A PromiseReactionJob is set as the native function of an extended
927 : * JSFunction object, with all information required for the job's
928 : * execution stored in in a reaction record in its first extended slot.
929 : */
930 : static bool
931 154 : PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp)
932 : {
933 154 : CallArgs args = CallArgsFromVp(argc, vp);
934 :
935 308 : RootedFunction job(cx, &args.callee().as<JSFunction>());
936 :
937 308 : RootedObject reactionObj(cx, &job->getExtendedSlot(ReactionJobSlot_ReactionRecord).toObject());
938 :
939 : // To ensure that the embedding ends up with the right entry global, we're
940 : // guaranteeing that the reaction job function gets created in the same
941 : // compartment as the handler function. That's not necessarily the global
942 : // that the job was triggered from, though.
943 : // We can find the triggering global via the job's reaction record. To go
944 : // back, we check if the reaction is a wrapper and if so, unwrap it and
945 : // enter its compartment.
946 308 : mozilla::Maybe<AutoCompartment> ac;
947 154 : if (!IsProxy(reactionObj)) {
948 143 : MOZ_RELEASE_ASSERT(reactionObj->is<PromiseReactionRecord>());
949 : } else {
950 11 : reactionObj = UncheckedUnwrap(reactionObj);
951 11 : if (JS_IsDeadWrapper(reactionObj)) {
952 0 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
953 0 : return false;
954 : }
955 11 : MOZ_RELEASE_ASSERT(reactionObj->is<PromiseReactionRecord>());
956 11 : ac.emplace(cx, reactionObj);
957 : }
958 :
959 : // Steps 1-2.
960 308 : Rooted<PromiseReactionRecord*> reaction(cx, &reactionObj->as<PromiseReactionRecord>());
961 154 : if (reaction->isAsyncFunctionAwait())
962 52 : return AsyncFunctionAwaitPromiseReactionJob(cx, reaction, args.rval());
963 102 : if (reaction->isAsyncGeneratorAwait())
964 0 : return AsyncGeneratorAwaitPromiseReactionJob(cx, reaction, args.rval());
965 :
966 : // Step 3.
967 204 : RootedValue handlerVal(cx, reaction->handler());
968 :
969 204 : RootedValue argument(cx, reaction->handlerArg());
970 :
971 204 : RootedValue handlerResult(cx);
972 102 : ResolutionMode resolutionMode = ResolveMode;
973 :
974 : // Steps 4-6.
975 102 : if (handlerVal.isNumber()) {
976 15 : int32_t handlerNum = int32_t(handlerVal.toNumber());
977 :
978 : // Step 4.
979 15 : if (handlerNum == PromiseHandlerIdentity) {
980 14 : handlerResult = argument;
981 1 : } else if (handlerNum == PromiseHandlerThrower) {
982 : // Step 5.
983 1 : resolutionMode = RejectMode;
984 1 : handlerResult = argument;
985 : } else {
986 0 : MOZ_ASSERT(handlerNum == PromiseHandlerAsyncIteratorValueUnwrapDone ||
987 : handlerNum == PromiseHandlerAsyncIteratorValueUnwrapNotDone);
988 :
989 0 : bool done = handlerNum == PromiseHandlerAsyncIteratorValueUnwrapDone;
990 : // Async Iteration proposal 6.1.1.2.1 step 1.
991 0 : RootedObject resultObj(cx, CreateIterResultObject(cx, argument, done));
992 0 : if (!resultObj)
993 0 : return false;
994 :
995 0 : handlerResult = ObjectValue(*resultObj);
996 : }
997 : } else {
998 : // Step 6.
999 174 : FixedInvokeArgs<1> args2(cx);
1000 87 : args2[0].set(argument);
1001 87 : if (!Call(cx, handlerVal, UndefinedHandleValue, args2, &handlerResult)) {
1002 0 : resolutionMode = RejectMode;
1003 0 : if (!MaybeGetAndClearException(cx, &handlerResult))
1004 0 : return false;
1005 : }
1006 : }
1007 :
1008 : // Steps 7-9.
1009 : size_t hookSlot = resolutionMode == RejectMode
1010 102 : ? ReactionRecordSlot_Reject
1011 102 : : ReactionRecordSlot_Resolve;
1012 204 : RootedObject callee(cx, reaction->getFixedSlot(hookSlot).toObjectOrNull());
1013 204 : RootedObject promiseObj(cx, reaction->promise());
1014 102 : if (!RunResolutionFunction(cx, callee, handlerResult, resolutionMode, promiseObj))
1015 0 : return false;
1016 :
1017 102 : args.rval().setUndefined();
1018 102 : return true;
1019 : }
1020 :
1021 : // ES2016, 25.4.2.2.
1022 : /**
1023 : * Callback for resolving a thenable, to be invoked by the embedding during
1024 : * its processing of the Promise job queue.
1025 : *
1026 : * See http://www.ecma-international.org/ecma-262/7.0/index.html#sec-jobs-and-job-queues
1027 : *
1028 : * A PromiseResolveThenableJob is set as the native function of an extended
1029 : * JSFunction object, with all information required for the job's
1030 : * execution stored in the function's extended slots.
1031 : *
1032 : * Usage of the function's extended slots is as follows:
1033 : * ThenableJobSlot_Handler: The handler to use as the Promise reaction.
1034 : * This can be PromiseHandlerIdentity,
1035 : * PromiseHandlerThrower, or a callable. In the
1036 : * latter case, it's guaranteed to be an object
1037 : * from the same compartment as the
1038 : * PromiseReactionJob.
1039 : * ThenableJobSlot_JobData: JobData - a, potentially CCW-wrapped, dense list
1040 : * containing data required for proper execution of
1041 : * the reaction.
1042 : *
1043 : * The JobData list has the following entries:
1044 : * ThenableJobDataSlot_Promise: The Promise to resolve using the given
1045 : * thenable.
1046 : * ThenableJobDataSlot_Thenable: The thenable to use as the receiver when
1047 : * calling the `then` function.
1048 : */
1049 : static bool
1050 81 : PromiseResolveThenableJob(JSContext* cx, unsigned argc, Value* vp)
1051 : {
1052 81 : CallArgs args = CallArgsFromVp(argc, vp);
1053 :
1054 162 : RootedFunction job(cx, &args.callee().as<JSFunction>());
1055 162 : RootedValue then(cx, job->getExtendedSlot(ThenableJobSlot_Handler));
1056 81 : MOZ_ASSERT(!IsWrapper(&then.toObject()));
1057 243 : RootedNativeObject jobArgs(cx, &job->getExtendedSlot(ThenableJobSlot_JobData)
1058 243 : .toObject().as<NativeObject>());
1059 :
1060 162 : RootedValue promise(cx, jobArgs->getDenseElement(ThenableJobDataIndex_Promise));
1061 162 : RootedValue thenable(cx, jobArgs->getDenseElement(ThenableJobDataIndex_Thenable));
1062 :
1063 : // Step 1.
1064 162 : RootedValue resolveVal(cx);
1065 162 : RootedValue rejectVal(cx);
1066 81 : if (!CreateResolvingFunctions(cx, promise, &resolveVal, &rejectVal))
1067 0 : return false;
1068 :
1069 : // Step 2.
1070 162 : FixedInvokeArgs<2> args2(cx);
1071 81 : args2[0].set(resolveVal);
1072 81 : args2[1].set(rejectVal);
1073 :
1074 162 : RootedValue rval(cx);
1075 :
1076 : // In difference to the usual pattern, we return immediately on success.
1077 81 : if (Call(cx, then, thenable, args2, &rval))
1078 81 : return true;
1079 :
1080 0 : if (!MaybeGetAndClearException(cx, &rval))
1081 0 : return false;
1082 :
1083 0 : FixedInvokeArgs<1> rejectArgs(cx);
1084 0 : rejectArgs[0].set(rval);
1085 :
1086 0 : return Call(cx, rejectVal, UndefinedHandleValue, rejectArgs, &rval);
1087 : }
1088 :
1089 : /**
1090 : * Tells the embedding to enqueue a Promise resolve thenable job, based on
1091 : * three parameters:
1092 : * promiseToResolve_ - The promise to resolve, obviously.
1093 : * thenable_ - The thenable to resolve the Promise with.
1094 : * thenVal - The `then` function to invoke with the `thenable` as the receiver.
1095 : */
1096 : static MOZ_MUST_USE bool
1097 81 : EnqueuePromiseResolveThenableJob(JSContext* cx, HandleValue promiseToResolve_,
1098 : HandleValue thenable_, HandleValue thenVal)
1099 : {
1100 : // Need to re-root these to enable wrapping them below.
1101 162 : RootedValue promiseToResolve(cx, promiseToResolve_);
1102 162 : RootedValue thenable(cx, thenable_);
1103 :
1104 : // We enter the `then` callable's compartment so that the job function is
1105 : // created in that compartment.
1106 : // That guarantees that the embedding ends up with the right entry global.
1107 : // This is relevant for some html APIs like fetch that derive information
1108 : // from said global.
1109 162 : RootedObject then(cx, CheckedUnwrap(&thenVal.toObject()));
1110 162 : AutoCompartment ac(cx, then);
1111 :
1112 162 : RootedAtom funName(cx, cx->names().empty);
1113 162 : RootedFunction job(cx, NewNativeFunction(cx, PromiseResolveThenableJob, 0, funName,
1114 162 : gc::AllocKind::FUNCTION_EXTENDED, GenericObject));
1115 81 : if (!job)
1116 0 : return false;
1117 :
1118 : // Store the `then` function on the callback.
1119 81 : job->setExtendedSlot(ThenableJobSlot_Handler, ObjectValue(*then));
1120 :
1121 : // Create a dense array to hold the data needed for the reaction job to
1122 : // work.
1123 : // See the doc comment for PromiseResolveThenableJob for the layout.
1124 162 : RootedArrayObject data(cx, NewDenseFullyAllocatedArray(cx, ThenableJobDataLength));
1125 162 : if (!data ||
1126 81 : data->ensureDenseElements(cx, 0, ThenableJobDataLength) != DenseElementResult::Success)
1127 : {
1128 0 : return false;
1129 : }
1130 :
1131 : // Wrap and set the `promiseToResolve` argument.
1132 81 : if (!cx->compartment()->wrap(cx, &promiseToResolve))
1133 0 : return false;
1134 81 : data->setDenseElement(ThenableJobDataIndex_Promise, promiseToResolve);
1135 : // At this point the promise is guaranteed to be wrapped into the job's
1136 : // compartment.
1137 162 : RootedObject promise(cx, &promiseToResolve.toObject());
1138 :
1139 : // Wrap and set the `thenable` argument.
1140 81 : MOZ_ASSERT(thenable.isObject());
1141 81 : if (!cx->compartment()->wrap(cx, &thenable))
1142 0 : return false;
1143 81 : data->setDenseElement(ThenableJobDataIndex_Thenable, thenable);
1144 :
1145 : // Store the data array on the reaction job.
1146 81 : job->setExtendedSlot(ThenableJobSlot_JobData, ObjectValue(*data));
1147 :
1148 162 : RootedObject incumbentGlobal(cx, cx->runtime()->getIncumbentGlobal(cx));
1149 81 : return cx->runtime()->enqueuePromiseJob(cx, job, promise, incumbentGlobal);
1150 : }
1151 :
1152 : static MOZ_MUST_USE bool
1153 : AddPromiseReaction(JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled,
1154 : HandleValue onRejected, HandleObject dependentPromise,
1155 : HandleObject resolve, HandleObject reject, HandleObject incumbentGlobal);
1156 :
1157 : static MOZ_MUST_USE bool
1158 : AddPromiseReaction(JSContext* cx, Handle<PromiseObject*> promise,
1159 : Handle<PromiseReactionRecord*> reaction);
1160 :
1161 : static MOZ_MUST_USE bool BlockOnPromise(JSContext* cx, HandleValue promise,
1162 : HandleObject blockedPromise,
1163 : HandleValue onFulfilled, HandleValue onRejected);
1164 :
1165 : static JSFunction*
1166 3 : GetResolveFunctionFromReject(JSFunction* reject)
1167 : {
1168 3 : MOZ_ASSERT(reject->maybeNative() == RejectPromiseFunction);
1169 3 : Value resolveFunVal = reject->getExtendedSlot(RejectFunctionSlot_ResolveFunction);
1170 3 : MOZ_ASSERT(IsNativeFunction(resolveFunVal, ResolvePromiseFunction));
1171 3 : return &resolveFunVal.toObject().as<JSFunction>();
1172 : }
1173 :
1174 : static JSFunction*
1175 89 : GetRejectFunctionFromResolve(JSFunction* resolve)
1176 : {
1177 89 : MOZ_ASSERT(resolve->maybeNative() == ResolvePromiseFunction);
1178 89 : Value rejectFunVal = resolve->getExtendedSlot(ResolveFunctionSlot_RejectFunction);
1179 89 : MOZ_ASSERT(IsNativeFunction(rejectFunVal, RejectPromiseFunction));
1180 89 : return &rejectFunVal.toObject().as<JSFunction>();
1181 : }
1182 :
1183 : static JSFunction*
1184 0 : GetResolveFunctionFromPromise(PromiseObject* promise)
1185 : {
1186 0 : Value rejectFunVal = promise->getFixedSlot(PromiseSlot_RejectFunction);
1187 0 : if (rejectFunVal.isUndefined())
1188 0 : return nullptr;
1189 0 : JSObject* rejectFunObj = &rejectFunVal.toObject();
1190 :
1191 : // We can safely unwrap it because all we want is to get the resolve
1192 : // function.
1193 0 : if (IsWrapper(rejectFunObj))
1194 0 : rejectFunObj = UncheckedUnwrap(rejectFunObj);
1195 :
1196 0 : if (!rejectFunObj->is<JSFunction>())
1197 0 : return nullptr;
1198 :
1199 0 : JSFunction* rejectFun = &rejectFunObj->as<JSFunction>();
1200 :
1201 : // Only the original RejectPromiseFunction has a reference to the resolve
1202 : // function.
1203 0 : if (rejectFun->maybeNative() != &RejectPromiseFunction)
1204 0 : return nullptr;
1205 :
1206 0 : return GetResolveFunctionFromReject(rejectFun);
1207 : }
1208 :
1209 : static void
1210 92 : ClearResolutionFunctionSlots(JSFunction* resolutionFun)
1211 : {
1212 : JSFunction* resolve;
1213 : JSFunction* reject;
1214 92 : if (resolutionFun->maybeNative() == ResolvePromiseFunction) {
1215 89 : resolve = resolutionFun;
1216 89 : reject = GetRejectFunctionFromResolve(resolutionFun);
1217 : } else {
1218 3 : resolve = GetResolveFunctionFromReject(resolutionFun);
1219 3 : reject = resolutionFun;
1220 : }
1221 :
1222 92 : resolve->setExtendedSlot(ResolveFunctionSlot_Promise, UndefinedValue());
1223 92 : resolve->setExtendedSlot(ResolveFunctionSlot_RejectFunction, UndefinedValue());
1224 :
1225 92 : reject->setExtendedSlot(RejectFunctionSlot_Promise, UndefinedValue());
1226 92 : reject->setExtendedSlot(RejectFunctionSlot_ResolveFunction, UndefinedValue());
1227 92 : }
1228 :
1229 : // ES2016, 25.4.3.1. steps 3-7.
1230 : static MOZ_MUST_USE PromiseObject*
1231 505 : CreatePromiseObjectInternal(JSContext* cx, HandleObject proto /* = nullptr */,
1232 : bool protoIsWrapped /* = false */, bool informDebugger /* = true */)
1233 : {
1234 : // Step 3.
1235 1010 : Rooted<PromiseObject*> promise(cx);
1236 : // Enter the unwrapped proto's compartment, if that's different from
1237 : // the current one.
1238 : // All state stored in a Promise's fixed slots must be created in the
1239 : // same compartment, so we get all of that out of the way here.
1240 : // (Except for the resolution functions, which are created below.)
1241 1010 : mozilla::Maybe<AutoCompartment> ac;
1242 505 : if (protoIsWrapped)
1243 0 : ac.emplace(cx, proto);
1244 :
1245 505 : promise = NewObjectWithClassProto<PromiseObject>(cx, proto);
1246 505 : if (!promise)
1247 0 : return nullptr;
1248 :
1249 : // Step 4.
1250 505 : promise->setFixedSlot(PromiseSlot_Flags, Int32Value(0));
1251 :
1252 : // Steps 5-6.
1253 : // Omitted, we allocate our single list of reaction records lazily.
1254 :
1255 : // Step 7.
1256 : // Implicit, the handled flag is unset by default.
1257 :
1258 : // Store an allocation stack so we can later figure out what the
1259 : // control flow was for some unexpected results. Frightfully expensive,
1260 : // but oh well.
1261 1010 : RootedObject stack(cx);
1262 505 : if (cx->options().asyncStack() || cx->compartment()->isDebuggee()) {
1263 505 : if (!JS::CaptureCurrentStack(cx, &stack, JS::StackCapture(JS::AllFrames())))
1264 0 : return nullptr;
1265 : }
1266 505 : promise->setFixedSlot(PromiseSlot_AllocationSite, ObjectOrNullValue(stack));
1267 505 : promise->setFixedSlot(PromiseSlot_AllocationTime, DoubleValue(MillisecondsSinceStartup()));
1268 :
1269 : // Let the Debugger know about this Promise.
1270 505 : if (informDebugger)
1271 409 : JS::dbg::onNewPromise(cx, promise);
1272 :
1273 505 : return promise;
1274 : }
1275 :
1276 : // ES2016, 25.4.3.1.
1277 : static bool
1278 96 : PromiseConstructor(JSContext* cx, unsigned argc, Value* vp)
1279 : {
1280 96 : CallArgs args = CallArgsFromVp(argc, vp);
1281 :
1282 : // Step 1.
1283 96 : if (!ThrowIfNotConstructing(cx, args, "Promise"))
1284 0 : return false;
1285 :
1286 : // Step 2.
1287 192 : RootedValue executorVal(cx, args.get(0));
1288 96 : if (!IsCallable(executorVal))
1289 0 : return ReportIsNotFunction(cx, executorVal);
1290 192 : RootedObject executor(cx, &executorVal.toObject());
1291 :
1292 : // Steps 3-10.
1293 192 : RootedObject newTarget(cx, &args.newTarget().toObject());
1294 96 : bool needsWrapping = false;
1295 :
1296 : // If the constructor is called via an Xray wrapper, then the newTarget
1297 : // hasn't been unwrapped. We want that because, while the actual instance
1298 : // should be created in the target compartment, the constructor's code
1299 : // should run in the wrapper's compartment.
1300 : //
1301 : // This is so that the resolve and reject callbacks get created in the
1302 : // wrapper's compartment, which is required for code in that compartment
1303 : // to freely interact with it, and, e.g., pass objects as arguments, which
1304 : // it wouldn't be able to if the callbacks were themselves wrapped in Xray
1305 : // wrappers.
1306 : //
1307 : // At the same time, just creating the Promise itself in the wrapper's
1308 : // compartment wouldn't be helpful: if the wrapper forbids interactions
1309 : // with objects except for specific actions, such as calling them, then
1310 : // the code we want to expose it to can't actually treat it as a Promise:
1311 : // calling .then on it would throw, for example.
1312 : //
1313 : // Another scenario where it's important to create the Promise in a
1314 : // different compartment from the resolution functions is when we want to
1315 : // give non-privileged code a Promise resolved with the result of a
1316 : // Promise from privileged code; as a return value of a JS-implemented
1317 : // API, say. If the resolution functions were unprivileged, then resolving
1318 : // with a privileged Promise would cause `resolve` to attempt accessing
1319 : // .then on the passed Promise, which would throw an exception, so we'd
1320 : // just end up with a rejected Promise. Really, we want to chain the two
1321 : // Promises, with the unprivileged one resolved with the resolution of the
1322 : // privileged one.
1323 96 : if (IsWrapper(newTarget)) {
1324 0 : JSObject* unwrappedNewTarget = CheckedUnwrap(newTarget);
1325 0 : MOZ_ASSERT(unwrappedNewTarget);
1326 0 : MOZ_ASSERT(unwrappedNewTarget != newTarget);
1327 :
1328 0 : newTarget = unwrappedNewTarget;
1329 : {
1330 0 : AutoCompartment ac(cx, newTarget);
1331 0 : RootedObject promiseCtor(cx);
1332 0 : if (!GetBuiltinConstructor(cx, JSProto_Promise, &promiseCtor))
1333 0 : return false;
1334 :
1335 : // Promise subclasses don't get the special Xray treatment, so
1336 : // we only need to do the complex wrapping and unwrapping scheme
1337 : // described above for instances of Promise itself.
1338 0 : if (newTarget == promiseCtor)
1339 0 : needsWrapping = true;
1340 : }
1341 : }
1342 :
1343 192 : RootedObject proto(cx);
1344 96 : if (needsWrapping) {
1345 0 : if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
1346 0 : return false;
1347 0 : if (!cx->compartment()->wrap(cx, &proto))
1348 0 : return false;
1349 : } else {
1350 96 : if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto))
1351 0 : return false;
1352 : }
1353 192 : Rooted<PromiseObject*> promise(cx, PromiseObject::create(cx, executor, proto, needsWrapping));
1354 96 : if (!promise)
1355 0 : return false;
1356 :
1357 : // Step 11.
1358 96 : args.rval().setObject(*promise);
1359 96 : if (needsWrapping)
1360 0 : return cx->compartment()->wrap(cx, args.rval());
1361 96 : return true;
1362 : }
1363 :
1364 : // ES2016, 25.4.3.1. steps 3-11.
1365 : /* static */ PromiseObject*
1366 96 : PromiseObject::create(JSContext* cx, HandleObject executor, HandleObject proto /* = nullptr */,
1367 : bool needsWrapping /* = false */)
1368 : {
1369 96 : MOZ_ASSERT(executor->isCallable());
1370 :
1371 192 : RootedObject usedProto(cx, proto);
1372 : // If the proto is wrapped, that means the current function is running
1373 : // with a different compartment active from the one the Promise instance
1374 : // is to be created in.
1375 : // See the comment in PromiseConstructor for details.
1376 96 : if (needsWrapping) {
1377 0 : MOZ_ASSERT(proto);
1378 0 : usedProto = CheckedUnwrap(proto);
1379 0 : if (!usedProto)
1380 0 : return nullptr;
1381 : }
1382 :
1383 :
1384 : // Steps 3-7.
1385 192 : Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx, usedProto, needsWrapping,
1386 192 : false));
1387 96 : if (!promise)
1388 0 : return nullptr;
1389 :
1390 192 : RootedValue promiseVal(cx, ObjectValue(*promise));
1391 96 : if (needsWrapping && !cx->compartment()->wrap(cx, &promiseVal))
1392 0 : return nullptr;
1393 :
1394 : // Step 8.
1395 : // The resolving functions are created in the compartment active when the
1396 : // (maybe wrapped) Promise constructor was called. They contain checks and
1397 : // can unwrap the Promise if required.
1398 192 : RootedValue resolveVal(cx);
1399 192 : RootedValue rejectVal(cx);
1400 96 : if (!CreateResolvingFunctions(cx, promiseVal, &resolveVal, &rejectVal))
1401 0 : return nullptr;
1402 :
1403 : // Need to wrap the resolution functions before storing them on the Promise.
1404 96 : if (needsWrapping) {
1405 0 : AutoCompartment ac(cx, promise);
1406 0 : RootedValue wrappedRejectVal(cx, rejectVal);
1407 0 : if (!cx->compartment()->wrap(cx, &wrappedRejectVal))
1408 0 : return nullptr;
1409 0 : promise->setFixedSlot(PromiseSlot_RejectFunction, wrappedRejectVal);
1410 : } else {
1411 96 : promise->setFixedSlot(PromiseSlot_RejectFunction, rejectVal);
1412 : }
1413 :
1414 : // Step 9.
1415 : bool success;
1416 : {
1417 192 : FixedInvokeArgs<2> args(cx);
1418 :
1419 96 : args[0].set(resolveVal);
1420 96 : args[1].set(rejectVal);
1421 :
1422 192 : RootedValue calleeOrRval(cx, ObjectValue(*executor));
1423 96 : success = Call(cx, calleeOrRval, UndefinedHandleValue, args, &calleeOrRval);
1424 : }
1425 :
1426 : // Step 10.
1427 96 : if (!success) {
1428 0 : RootedValue exceptionVal(cx);
1429 0 : if (!MaybeGetAndClearException(cx, &exceptionVal))
1430 0 : return nullptr;
1431 :
1432 0 : FixedInvokeArgs<1> args(cx);
1433 :
1434 0 : args[0].set(exceptionVal);
1435 :
1436 : // |rejectVal| is unused after this, so we can safely write to it.
1437 0 : if (!Call(cx, rejectVal, UndefinedHandleValue, args, &rejectVal))
1438 0 : return nullptr;
1439 : }
1440 :
1441 : // Let the Debugger know about this Promise.
1442 96 : JS::dbg::onNewPromise(cx, promise);
1443 :
1444 : // Step 11.
1445 96 : return promise;
1446 : }
1447 :
1448 : // ES2016, 25.4.3.1. skipping creation of resolution functions and executor
1449 : // function invocation.
1450 : /* static */ PromiseObject*
1451 2 : PromiseObject::createSkippingExecutor(JSContext* cx)
1452 : {
1453 2 : return CreatePromiseObjectWithoutResolutionFunctions(cx);
1454 : }
1455 :
1456 : static MOZ_MUST_USE bool PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator,
1457 : HandleObject C, HandleObject promiseObj,
1458 : HandleObject resolve, HandleObject reject,
1459 : bool* done);
1460 :
1461 : // ES2016, 25.4.4.1.
1462 : static bool
1463 3 : Promise_static_all(JSContext* cx, unsigned argc, Value* vp)
1464 : {
1465 3 : CallArgs args = CallArgsFromVp(argc, vp);
1466 6 : RootedValue iterable(cx, args.get(0));
1467 :
1468 : // Step 2 (reordered).
1469 6 : RootedValue CVal(cx, args.thisv());
1470 3 : if (!CVal.isObject()) {
1471 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
1472 0 : "Receiver of Promise.all call");
1473 0 : return false;
1474 : }
1475 :
1476 : // Step 1.
1477 6 : RootedObject C(cx, &CVal.toObject());
1478 :
1479 : // Step 3.
1480 6 : RootedObject resultPromise(cx);
1481 6 : RootedObject resolve(cx);
1482 6 : RootedObject reject(cx);
1483 3 : if (!NewPromiseCapability(cx, C, &resultPromise, &resolve, &reject, false))
1484 0 : return false;
1485 :
1486 : // Steps 4-5.
1487 6 : JS::ForOfIterator iter(cx);
1488 3 : if (!iter.init(iterable, JS::ForOfIterator::AllowNonIterable))
1489 0 : return AbruptRejectPromise(cx, args, resultPromise, reject);
1490 :
1491 3 : if (!iter.valueIsIterable()) {
1492 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE,
1493 0 : "Argument of Promise.all");
1494 0 : return AbruptRejectPromise(cx, args, resultPromise, reject);
1495 : }
1496 :
1497 : // Step 6 (implicit).
1498 :
1499 : // Step 7.
1500 : bool done;
1501 3 : bool result = PerformPromiseAll(cx, iter, C, resultPromise, resolve, reject, &done);
1502 :
1503 : // Step 8.
1504 3 : if (!result) {
1505 : // Step 8.a.
1506 0 : if (!done)
1507 0 : iter.closeThrow();
1508 :
1509 : // Step 8.b.
1510 0 : return AbruptRejectPromise(cx, args, resultPromise, reject);
1511 : }
1512 :
1513 : // Step 9.
1514 3 : args.rval().setObject(*resultPromise);
1515 3 : return true;
1516 : }
1517 :
1518 : static MOZ_MUST_USE bool PerformPromiseThen(JSContext* cx, Handle<PromiseObject*> promise,
1519 : HandleValue onFulfilled_, HandleValue onRejected_,
1520 : HandleObject resultPromise,
1521 : HandleObject resolve, HandleObject reject);
1522 :
1523 : static bool PromiseAllResolveElementFunction(JSContext* cx, unsigned argc, Value* vp);
1524 :
1525 : // Unforgeable version of ES2016, 25.4.4.1.
1526 : MOZ_MUST_USE JSObject*
1527 0 : js::GetWaitForAllPromise(JSContext* cx, const JS::AutoObjectVector& promises)
1528 : {
1529 : #ifdef DEBUG
1530 0 : for (size_t i = 0, len = promises.length(); i < len; i++) {
1531 0 : JSObject* obj = promises[i];
1532 0 : assertSameCompartment(cx, obj);
1533 0 : MOZ_ASSERT(UncheckedUnwrap(obj)->is<PromiseObject>());
1534 : }
1535 : #endif
1536 :
1537 : // Step 1.
1538 0 : RootedObject C(cx, GlobalObject::getOrCreatePromiseConstructor(cx, cx->global()));
1539 0 : if (!C)
1540 0 : return nullptr;
1541 :
1542 : // Step 2 (omitted).
1543 :
1544 : // Step 3.
1545 0 : RootedObject resultPromise(cx);
1546 0 : RootedObject resolve(cx);
1547 0 : RootedObject reject(cx);
1548 0 : if (!NewPromiseCapability(cx, C, &resultPromise, &resolve, &reject, false))
1549 0 : return nullptr;
1550 :
1551 : // Steps 4-6 (omitted).
1552 :
1553 : // Step 7.
1554 : // Implemented as an inlined, simplied version of ES2016 25.4.4.1.1, PerformPromiseAll.
1555 : {
1556 0 : uint32_t promiseCount = promises.length();
1557 : // Sub-steps 1-2 (omitted).
1558 :
1559 : // Sub-step 3.
1560 0 : RootedNativeObject valuesArray(cx, NewDenseFullyAllocatedArray(cx, promiseCount));
1561 0 : if (!valuesArray)
1562 0 : return nullptr;
1563 0 : if (valuesArray->ensureDenseElements(cx, 0, promiseCount) != DenseElementResult::Success)
1564 0 : return nullptr;
1565 :
1566 : // Sub-step 4.
1567 : // Create our data holder that holds all the things shared across
1568 : // every step of the iterator. In particular, this holds the
1569 : // remainingElementsCount (as an integer reserved slot), the array of
1570 : // values, and the resolve function from our PromiseCapability.
1571 0 : RootedValue valuesArrayVal(cx, ObjectValue(*valuesArray));
1572 0 : Rooted<PromiseAllDataHolder*> dataHolder(cx, NewPromiseAllDataHolder(cx, resultPromise,
1573 : valuesArrayVal,
1574 0 : resolve));
1575 0 : if (!dataHolder)
1576 0 : return nullptr;
1577 0 : RootedValue dataHolderVal(cx, ObjectValue(*dataHolder));
1578 :
1579 : // Sub-step 5 (inline in loop-header below).
1580 :
1581 : // Sub-step 6.
1582 0 : for (uint32_t index = 0; index < promiseCount; index++) {
1583 : // Steps a-c (omitted).
1584 : // Step d (implemented after the loop).
1585 : // Steps e-g (omitted).
1586 :
1587 : // Step h.
1588 0 : valuesArray->setDenseElement(index, UndefinedHandleValue);
1589 :
1590 : // Step i, vastly simplified.
1591 0 : RootedObject nextPromiseObj(cx, promises[index]);
1592 :
1593 : // Step j.
1594 0 : RootedFunction resolveFunc(cx, NewNativeFunction(cx, PromiseAllResolveElementFunction,
1595 : 1, nullptr,
1596 : gc::AllocKind::FUNCTION_EXTENDED,
1597 0 : GenericObject));
1598 0 : if (!resolveFunc)
1599 0 : return nullptr;
1600 :
1601 : // Steps k-o.
1602 0 : resolveFunc->setExtendedSlot(PromiseAllResolveElementFunctionSlot_Data, dataHolderVal);
1603 0 : resolveFunc->setExtendedSlot(PromiseAllResolveElementFunctionSlot_ElementIndex,
1604 0 : Int32Value(index));
1605 :
1606 : // Step p.
1607 0 : dataHolder->increaseRemainingCount();
1608 :
1609 : // Step q, very roughly.
1610 0 : RootedValue resolveFunVal(cx, ObjectValue(*resolveFunc));
1611 0 : RootedValue rejectFunVal(cx, ObjectValue(*reject));
1612 0 : Rooted<PromiseObject*> nextPromise(cx);
1613 :
1614 : // GetWaitForAllPromise is used internally only and must not
1615 : // trigger content-observable effects when registering a reaction.
1616 : // It's also meant to work on wrapped Promises, potentially from
1617 : // compartments with principals inaccessible from the current
1618 : // compartment. To make that work, it unwraps promises with
1619 : // UncheckedUnwrap,
1620 0 : nextPromise = &UncheckedUnwrap(nextPromiseObj)->as<PromiseObject>();
1621 :
1622 0 : if (!PerformPromiseThen(cx, nextPromise, resolveFunVal, rejectFunVal,
1623 : resultPromise, nullptr, nullptr))
1624 : {
1625 0 : return nullptr;
1626 : }
1627 :
1628 : // Step r (inline in loop-header).
1629 : }
1630 :
1631 : // Sub-step d.i (implicit).
1632 : // Sub-step d.ii.
1633 0 : int32_t remainingCount = dataHolder->decreaseRemainingCount();
1634 :
1635 : // Sub-step d.iii-iv.
1636 0 : if (remainingCount == 0) {
1637 0 : RootedValue valuesArrayVal(cx, ObjectValue(*valuesArray));
1638 0 : if (!ResolvePromiseInternal(cx, resultPromise, valuesArrayVal))
1639 0 : return nullptr;
1640 : }
1641 : }
1642 :
1643 : // Step 8 (omitted).
1644 :
1645 : // Step 9.
1646 0 : return resultPromise;
1647 : }
1648 :
1649 : static MOZ_MUST_USE bool
1650 120 : RunResolutionFunction(JSContext *cx, HandleObject resolutionFun, HandleValue result,
1651 : ResolutionMode mode, HandleObject promiseObj)
1652 : {
1653 : // The absence of a resolve/reject function can mean that, as an
1654 : // optimization, those weren't created. In that case, a flag is set on
1655 : // the Promise object. (It's also possible to not have a resolution
1656 : // function without that flag being set. This can occur if a Promise
1657 : // subclass constructor passes null/undefined to `super()`.)
1658 : // There are also reactions where the Promise itself is missing. For
1659 : // those, there's nothing left to do here.
1660 120 : assertSameCompartment(cx, resolutionFun);
1661 120 : assertSameCompartment(cx, result);
1662 120 : assertSameCompartment(cx, promiseObj);
1663 120 : if (resolutionFun) {
1664 2 : RootedValue calleeOrRval(cx, ObjectValue(*resolutionFun));
1665 2 : FixedInvokeArgs<1> resolveArgs(cx);
1666 1 : resolveArgs[0].set(result);
1667 1 : return Call(cx, calleeOrRval, UndefinedHandleValue, resolveArgs, &calleeOrRval);
1668 : }
1669 :
1670 119 : if (!promiseObj)
1671 0 : return true;
1672 :
1673 238 : Rooted<PromiseObject*> promise(cx, &promiseObj->as<PromiseObject>());
1674 119 : if (promise->state() != JS::PromiseState::Pending)
1675 1 : return true;
1676 :
1677 118 : if (mode == ResolveMode) {
1678 117 : if (!PromiseHasAnyFlag(*promise, PROMISE_FLAG_DEFAULT_RESOLVE_FUNCTION))
1679 4 : return true;
1680 113 : return ResolvePromiseInternal(cx, promise, result);
1681 : }
1682 :
1683 1 : if (!PromiseHasAnyFlag(*promise, PROMISE_FLAG_DEFAULT_REJECT_FUNCTION))
1684 0 : return true;
1685 1 : return RejectMaybeWrappedPromise(cx, promiseObj, result);
1686 : }
1687 :
1688 : // ES2016, 25.4.4.1.1.
1689 : static MOZ_MUST_USE bool
1690 3 : PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
1691 : HandleObject promiseObj, HandleObject resolve, HandleObject reject,
1692 : bool* done)
1693 : {
1694 3 : *done = false;
1695 :
1696 6 : RootedObject unwrappedPromiseObj(cx);
1697 3 : if (IsWrapper(promiseObj)) {
1698 0 : unwrappedPromiseObj = CheckedUnwrap(promiseObj);
1699 0 : MOZ_ASSERT(unwrappedPromiseObj);
1700 : }
1701 :
1702 : // Step 1.
1703 3 : MOZ_ASSERT(C->isConstructor());
1704 6 : RootedValue CVal(cx, ObjectValue(*C));
1705 :
1706 : // Step 2 (omitted).
1707 :
1708 : // Step 3.
1709 : // We have to be very careful about which compartments we create things in
1710 : // here. In particular, we have to maintain the invariant that anything
1711 : // stored in a reserved slot is same-compartment with the object whose
1712 : // reserved slot it's in. But we want to create the values array in the
1713 : // Promise's compartment, because that array can get exposed to
1714 : // code that has access to the Promise (in particular code from
1715 : // that compartment), and that should work, even if the Promise
1716 : // compartment is less-privileged than our caller compartment.
1717 : //
1718 : // So the plan is as follows: Create the values array in the promise
1719 : // compartment. Create the PromiseAllResolveElement function
1720 : // and the data holder in our current compartment. Store a
1721 : // cross-compartment wrapper to the values array in the holder. This
1722 : // should be OK because the only things we hand the
1723 : // PromiseAllResolveElement function to are the "then" calls we do and in
1724 : // the case when the Promise's compartment is not the current compartment
1725 : // those are happening over Xrays anyway, which means they get the
1726 : // canonical "then" function and content can't see our
1727 : // PromiseAllResolveElement.
1728 6 : RootedObject valuesArray(cx);
1729 3 : if (unwrappedPromiseObj) {
1730 0 : JSAutoCompartment ac(cx, unwrappedPromiseObj);
1731 0 : valuesArray = NewDenseFullyAllocatedArray(cx, 0);
1732 : } else {
1733 3 : valuesArray = NewDenseFullyAllocatedArray(cx, 0);
1734 : }
1735 3 : if (!valuesArray)
1736 0 : return false;
1737 :
1738 6 : RootedValue valuesArrayVal(cx, ObjectValue(*valuesArray));
1739 3 : if (!cx->compartment()->wrap(cx, &valuesArrayVal))
1740 0 : return false;
1741 :
1742 : // Step 4.
1743 : // Create our data holder that holds all the things shared across
1744 : // every step of the iterator. In particular, this holds the
1745 : // remainingElementsCount (as an integer reserved slot), the array of
1746 : // values, and the resolve function from our PromiseCapability.
1747 6 : Rooted<PromiseAllDataHolder*> dataHolder(cx, NewPromiseAllDataHolder(cx, promiseObj,
1748 6 : valuesArrayVal, resolve));
1749 3 : if (!dataHolder)
1750 0 : return false;
1751 6 : RootedValue dataHolderVal(cx, ObjectValue(*dataHolder));
1752 :
1753 : // Step 5.
1754 3 : uint32_t index = 0;
1755 :
1756 : // Step 6.
1757 6 : RootedValue nextValue(cx);
1758 6 : RootedId indexId(cx);
1759 6 : RootedValue rejectFunVal(cx, ObjectValue(*reject));
1760 :
1761 : while (true) {
1762 : // Steps a-c, e-g.
1763 11 : if (!iterator.next(&nextValue, done)) {
1764 : // Steps b, f.
1765 0 : *done = true;
1766 :
1767 : // Steps c, g.
1768 3 : return false;
1769 : }
1770 :
1771 : // Step d.
1772 11 : if (*done) {
1773 : // Step d.i (implicit).
1774 :
1775 : // Step d.ii.
1776 3 : int32_t remainingCount = dataHolder->decreaseRemainingCount();
1777 :
1778 : // Steps d.iii-iv.
1779 3 : if (remainingCount == 0) {
1780 0 : return RunResolutionFunction(cx, resolve, valuesArrayVal, ResolveMode,
1781 0 : promiseObj);
1782 : }
1783 :
1784 : // We're all set for now!
1785 3 : return true;
1786 : }
1787 :
1788 : // Step h.
1789 : { // Scope for the JSAutoCompartment we need to work with valuesArray. We
1790 : // mostly do this for performance; we could go ahead and do the define via
1791 : // a cross-compartment proxy instead...
1792 16 : JSAutoCompartment ac(cx, valuesArray);
1793 8 : indexId = INT_TO_JSID(index);
1794 8 : if (!DefineProperty(cx, valuesArray, indexId, UndefinedHandleValue))
1795 0 : return false;
1796 : }
1797 :
1798 : // Step i.
1799 : // Sadly, because someone could have overridden
1800 : // "resolve" on the canonical Promise constructor.
1801 16 : RootedValue nextPromise(cx);
1802 16 : RootedValue staticResolve(cx);
1803 8 : if (!GetProperty(cx, CVal, cx->names().resolve, &staticResolve))
1804 0 : return false;
1805 :
1806 16 : FixedInvokeArgs<1> resolveArgs(cx);
1807 8 : resolveArgs[0].set(nextValue);
1808 8 : if (!Call(cx, staticResolve, CVal, resolveArgs, &nextPromise))
1809 0 : return false;
1810 :
1811 : // Step j.
1812 16 : RootedFunction resolveFunc(cx, NewNativeFunction(cx, PromiseAllResolveElementFunction,
1813 : 1, nullptr,
1814 : gc::AllocKind::FUNCTION_EXTENDED,
1815 16 : GenericObject));
1816 8 : if (!resolveFunc)
1817 0 : return false;
1818 :
1819 : // Steps k,m,n.
1820 8 : resolveFunc->setExtendedSlot(PromiseAllResolveElementFunctionSlot_Data, dataHolderVal);
1821 :
1822 : // Step l.
1823 8 : resolveFunc->setExtendedSlot(PromiseAllResolveElementFunctionSlot_ElementIndex,
1824 16 : Int32Value(index));
1825 :
1826 : // Steps o-p.
1827 8 : dataHolder->increaseRemainingCount();
1828 :
1829 : // Step q.
1830 16 : RootedValue resolveFunVal(cx, ObjectValue(*resolveFunc));
1831 8 : if (!BlockOnPromise(cx, nextPromise, promiseObj, resolveFunVal, rejectFunVal))
1832 0 : return false;
1833 :
1834 : // Step r.
1835 8 : index++;
1836 8 : MOZ_ASSERT(index > 0);
1837 8 : }
1838 : }
1839 :
1840 : // ES2016, 25.4.4.1.2.
1841 : static bool
1842 5 : PromiseAllResolveElementFunction(JSContext* cx, unsigned argc, Value* vp)
1843 : {
1844 5 : CallArgs args = CallArgsFromVp(argc, vp);
1845 :
1846 10 : RootedFunction resolve(cx, &args.callee().as<JSFunction>());
1847 10 : RootedValue xVal(cx, args.get(0));
1848 :
1849 : // Step 1.
1850 10 : RootedValue dataVal(cx, resolve->getExtendedSlot(PromiseAllResolveElementFunctionSlot_Data));
1851 :
1852 : // Step 2.
1853 : // We use the existence of the data holder as a signal for whether the
1854 : // Promise was already resolved. Upon resolution, it's reset to
1855 : // `undefined`.
1856 5 : if (dataVal.isUndefined()) {
1857 0 : args.rval().setUndefined();
1858 0 : return true;
1859 : }
1860 :
1861 10 : Rooted<PromiseAllDataHolder*> data(cx, &dataVal.toObject().as<PromiseAllDataHolder>());
1862 :
1863 : // Step 3.
1864 5 : resolve->setExtendedSlot(PromiseAllResolveElementFunctionSlot_Data, UndefinedValue());
1865 :
1866 : // Step 4.
1867 5 : int32_t index = resolve->getExtendedSlot(PromiseAllResolveElementFunctionSlot_ElementIndex)
1868 5 : .toInt32();
1869 :
1870 : // Step 5.
1871 10 : RootedValue valuesVal(cx, data->valuesArray());
1872 10 : RootedObject valuesObj(cx, &valuesVal.toObject());
1873 5 : bool valuesListIsWrapped = false;
1874 5 : if (IsWrapper(valuesObj)) {
1875 0 : valuesListIsWrapped = true;
1876 : // See comment for PerformPromiseAll, step 3 for why we unwrap here.
1877 0 : valuesObj = UncheckedUnwrap(valuesObj);
1878 : }
1879 10 : RootedNativeObject values(cx, &valuesObj->as<NativeObject>());
1880 :
1881 : // Step 6 (moved under step 10).
1882 : // Step 7 (moved to step 9).
1883 :
1884 : // Step 8.
1885 : // The index is guaranteed to be initialized to `undefined`.
1886 5 : if (valuesListIsWrapped) {
1887 0 : AutoCompartment ac(cx, values);
1888 0 : if (!cx->compartment()->wrap(cx, &xVal))
1889 0 : return false;
1890 : }
1891 5 : values->setDenseElement(index, xVal);
1892 :
1893 : // Steps 7,9.
1894 5 : uint32_t remainingCount = data->decreaseRemainingCount();
1895 :
1896 : // Step 10.
1897 5 : if (remainingCount == 0) {
1898 : // Step 10.a. (Omitted, happened in PerformPromiseAll.)
1899 : // Step 10.b.
1900 :
1901 : // Step 6 (Adapted to work with PromiseAllDataHolder's layout).
1902 2 : RootedObject resolveAllFun(cx, data->resolveObj());
1903 2 : RootedObject promiseObj(cx, data->promiseObj());
1904 1 : if (!RunResolutionFunction(cx, resolveAllFun, valuesVal, ResolveMode, promiseObj))
1905 0 : return false;
1906 : }
1907 :
1908 : // Step 11.
1909 5 : args.rval().setUndefined();
1910 5 : return true;
1911 : }
1912 :
1913 : static MOZ_MUST_USE bool PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator,
1914 : HandleObject C, HandleObject promiseObj,
1915 : HandleObject resolve, HandleObject reject,
1916 : bool* done);
1917 :
1918 : // ES2016, 25.4.4.3.
1919 : static bool
1920 0 : Promise_static_race(JSContext* cx, unsigned argc, Value* vp)
1921 : {
1922 0 : CallArgs args = CallArgsFromVp(argc, vp);
1923 0 : RootedValue iterable(cx, args.get(0));
1924 :
1925 : // Step 2 (reordered).
1926 0 : RootedValue CVal(cx, args.thisv());
1927 0 : if (!CVal.isObject()) {
1928 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
1929 0 : "Receiver of Promise.race call");
1930 0 : return false;
1931 : }
1932 :
1933 : // Step 1.
1934 0 : RootedObject C(cx, &CVal.toObject());
1935 :
1936 : // Step 3.
1937 0 : RootedObject resultPromise(cx);
1938 0 : RootedObject resolve(cx);
1939 0 : RootedObject reject(cx);
1940 0 : if (!NewPromiseCapability(cx, C, &resultPromise, &resolve, &reject, false))
1941 0 : return false;
1942 :
1943 : // Steps 4-5.
1944 0 : JS::ForOfIterator iter(cx);
1945 0 : if (!iter.init(iterable, JS::ForOfIterator::AllowNonIterable))
1946 0 : return AbruptRejectPromise(cx, args, resultPromise, reject);
1947 :
1948 0 : if (!iter.valueIsIterable()) {
1949 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE,
1950 0 : "Argument of Promise.race");
1951 0 : return AbruptRejectPromise(cx, args, resultPromise, reject);
1952 : }
1953 :
1954 : // Step 6 (implicit).
1955 :
1956 : // Step 7.
1957 : bool done;
1958 0 : bool result = PerformPromiseRace(cx, iter, C, resultPromise, resolve, reject, &done);
1959 :
1960 : // Step 8.
1961 0 : if (!result) {
1962 : // Step 8.a.
1963 0 : if (!done)
1964 0 : iter.closeThrow();
1965 :
1966 : // Step 8.b.
1967 0 : return AbruptRejectPromise(cx, args, resultPromise, reject);
1968 : }
1969 :
1970 : // Step 9.
1971 0 : args.rval().setObject(*resultPromise);
1972 0 : return true;
1973 : }
1974 :
1975 : // ES2016, 25.4.4.3.1.
1976 : static MOZ_MUST_USE bool
1977 0 : PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
1978 : HandleObject promiseObj, HandleObject resolve, HandleObject reject,
1979 : bool* done)
1980 : {
1981 0 : *done = false;
1982 0 : MOZ_ASSERT(C->isConstructor());
1983 0 : RootedValue CVal(cx, ObjectValue(*C));
1984 :
1985 0 : RootedValue nextValue(cx);
1986 0 : RootedValue resolveFunVal(cx, ObjectValue(*resolve));
1987 0 : RootedValue rejectFunVal(cx, ObjectValue(*reject));
1988 :
1989 : while (true) {
1990 : // Steps a-c, e-g.
1991 0 : if (!iterator.next(&nextValue, done)) {
1992 : // Steps b, f.
1993 0 : *done = true;
1994 :
1995 : // Steps c, g.
1996 0 : return false;
1997 : }
1998 :
1999 : // Step d.
2000 0 : if (*done) {
2001 : // Step d.i (implicit).
2002 :
2003 : // Step d.ii.
2004 0 : return true;
2005 : }
2006 :
2007 : // Step h.
2008 : // Sadly, because someone could have overridden
2009 : // "resolve" on the canonical Promise constructor.
2010 0 : RootedValue nextPromise(cx);
2011 0 : RootedValue staticResolve(cx);
2012 0 : if (!GetProperty(cx, CVal, cx->names().resolve, &staticResolve))
2013 0 : return false;
2014 :
2015 0 : FixedInvokeArgs<1> resolveArgs(cx);
2016 0 : resolveArgs[0].set(nextValue);
2017 0 : if (!Call(cx, staticResolve, CVal, resolveArgs, &nextPromise))
2018 0 : return false;
2019 :
2020 : // Step i.
2021 0 : if (!BlockOnPromise(cx, nextPromise, promiseObj, resolveFunVal, rejectFunVal))
2022 0 : return false;
2023 0 : }
2024 :
2025 : MOZ_ASSERT_UNREACHABLE("Shouldn't reach the end of PerformPromiseRace");
2026 : }
2027 :
2028 : // ES2016, Sub-steps of 25.4.4.4 and 25.4.4.5.
2029 : static MOZ_MUST_USE JSObject*
2030 22 : CommonStaticResolveRejectImpl(JSContext* cx, HandleValue thisVal, HandleValue argVal,
2031 : ResolutionMode mode)
2032 : {
2033 : // Steps 1-2.
2034 22 : if (!thisVal.isObject()) {
2035 : const char* msg = mode == ResolveMode
2036 0 : ? "Receiver of Promise.resolve call"
2037 0 : : "Receiver of Promise.reject call";
2038 0 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, msg);
2039 0 : return nullptr;
2040 : }
2041 44 : RootedObject C(cx, &thisVal.toObject());
2042 :
2043 : // Step 3 of Resolve.
2044 22 : if (mode == ResolveMode && argVal.isObject()) {
2045 25 : RootedObject xObj(cx, &argVal.toObject());
2046 15 : bool isPromise = false;
2047 15 : if (xObj->is<PromiseObject>()) {
2048 5 : isPromise = true;
2049 10 : } else if (IsWrapper(xObj)) {
2050 : // Treat instances of Promise from other compartments as Promises
2051 : // here, too.
2052 : // It's important to do the GetProperty for the `constructor`
2053 : // below through the wrapper, because wrappers can change the
2054 : // outcome, so instead of unwrapping and then performing the
2055 : // GetProperty, just check here and then operate on the original
2056 : // object again.
2057 16 : RootedObject unwrappedObject(cx, CheckedUnwrap(xObj));
2058 8 : if (unwrappedObject && unwrappedObject->is<PromiseObject>())
2059 5 : isPromise = true;
2060 : }
2061 15 : if (isPromise) {
2062 15 : RootedValue ctorVal(cx);
2063 10 : if (!GetProperty(cx, xObj, xObj, cx->names().constructor, &ctorVal))
2064 0 : return nullptr;
2065 10 : if (ctorVal == thisVal)
2066 5 : return xObj;
2067 : }
2068 : }
2069 :
2070 : // Step 4 of Resolve, 3 of Reject.
2071 34 : RootedObject promise(cx);
2072 34 : RootedObject resolveFun(cx);
2073 34 : RootedObject rejectFun(cx);
2074 17 : if (!NewPromiseCapability(cx, C, &promise, &resolveFun, &rejectFun, true))
2075 0 : return nullptr;
2076 :
2077 : // Step 5 of Resolve, 4 of Reject.
2078 17 : if (!RunResolutionFunction(cx, mode == ResolveMode ? resolveFun : rejectFun, argVal, mode,
2079 : promise))
2080 : {
2081 0 : return nullptr;
2082 : }
2083 :
2084 : // Step 6 of Resolve, 4 of Reject.
2085 17 : return promise;
2086 : }
2087 :
2088 : /**
2089 : * ES2016, 25.4.4.4, Promise.reject.
2090 : */
2091 : bool
2092 0 : js::Promise_reject(JSContext* cx, unsigned argc, Value* vp)
2093 : {
2094 0 : CallArgs args = CallArgsFromVp(argc, vp);
2095 0 : RootedValue thisVal(cx, args.thisv());
2096 0 : RootedValue argVal(cx, args.get(0));
2097 0 : JSObject* result = CommonStaticResolveRejectImpl(cx, thisVal, argVal, RejectMode);
2098 0 : if (!result)
2099 0 : return false;
2100 0 : args.rval().setObject(*result);
2101 0 : return true;
2102 : }
2103 :
2104 : /**
2105 : * Unforgeable version of ES2016, 25.4.4.4, Promise.reject.
2106 : */
2107 : /* static */ JSObject*
2108 0 : PromiseObject::unforgeableReject(JSContext* cx, HandleValue value)
2109 : {
2110 0 : RootedObject promiseCtor(cx, JS::GetPromiseConstructor(cx));
2111 0 : if (!promiseCtor)
2112 0 : return nullptr;
2113 0 : RootedValue cVal(cx, ObjectValue(*promiseCtor));
2114 0 : return CommonStaticResolveRejectImpl(cx, cVal, value, RejectMode);
2115 : }
2116 :
2117 : /**
2118 : * ES2016, 25.4.4.5, Promise.resolve.
2119 : */
2120 : bool
2121 22 : js::Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp)
2122 : {
2123 22 : CallArgs args = CallArgsFromVp(argc, vp);
2124 44 : RootedValue thisVal(cx, args.thisv());
2125 44 : RootedValue argVal(cx, args.get(0));
2126 22 : JSObject* result = CommonStaticResolveRejectImpl(cx, thisVal, argVal, ResolveMode);
2127 22 : if (!result)
2128 0 : return false;
2129 22 : args.rval().setObject(*result);
2130 22 : return true;
2131 : }
2132 :
2133 : /**
2134 : * Unforgeable version of ES2016, 25.4.4.5, Promise.resolve.
2135 : */
2136 : /* static */ JSObject*
2137 0 : PromiseObject::unforgeableResolve(JSContext* cx, HandleValue value)
2138 : {
2139 0 : RootedObject promiseCtor(cx, JS::GetPromiseConstructor(cx));
2140 0 : if (!promiseCtor)
2141 0 : return nullptr;
2142 0 : RootedValue cVal(cx, ObjectValue(*promiseCtor));
2143 0 : return CommonStaticResolveRejectImpl(cx, cVal, value, ResolveMode);
2144 : }
2145 :
2146 : // ES2016, 25.4.4.6, implemented in Promise.js.
2147 :
2148 : // ES2016, 25.4.5.1, implemented in Promise.js.
2149 :
2150 : static PromiseReactionRecord*
2151 346 : NewReactionRecord(JSContext* cx, HandleObject resultPromise, HandleValue onFulfilled,
2152 : HandleValue onRejected, HandleObject resolve, HandleObject reject,
2153 : HandleObject incumbentGlobalObject)
2154 : {
2155 692 : Rooted<PromiseReactionRecord*> reaction(cx, NewObjectWithClassProto<PromiseReactionRecord>(cx));
2156 346 : if (!reaction)
2157 0 : return nullptr;
2158 :
2159 346 : assertSameCompartment(cx, resultPromise);
2160 346 : assertSameCompartment(cx, onFulfilled);
2161 346 : assertSameCompartment(cx, onRejected);
2162 346 : assertSameCompartment(cx, resolve);
2163 346 : assertSameCompartment(cx, reject);
2164 346 : assertSameCompartment(cx, incumbentGlobalObject);
2165 :
2166 346 : reaction->setFixedSlot(ReactionRecordSlot_Promise, ObjectOrNullValue(resultPromise));
2167 346 : reaction->setFixedSlot(ReactionRecordSlot_Flags, Int32Value(0));
2168 346 : reaction->setFixedSlot(ReactionRecordSlot_OnFulfilled, onFulfilled);
2169 346 : reaction->setFixedSlot(ReactionRecordSlot_OnRejected, onRejected);
2170 346 : reaction->setFixedSlot(ReactionRecordSlot_Resolve, ObjectOrNullValue(resolve));
2171 346 : reaction->setFixedSlot(ReactionRecordSlot_Reject, ObjectOrNullValue(reject));
2172 346 : reaction->setFixedSlot(ReactionRecordSlot_IncumbentGlobalObject,
2173 692 : ObjectOrNullValue(incumbentGlobalObject));
2174 :
2175 346 : return reaction;
2176 : }
2177 :
2178 : // ES2016, 25.4.5.3., steps 3-5.
2179 : MOZ_MUST_USE bool
2180 267 : js::OriginalPromiseThen(JSContext* cx, Handle<PromiseObject*> promise,
2181 : HandleValue onFulfilled, HandleValue onRejected,
2182 : MutableHandleObject dependent, bool createDependent)
2183 : {
2184 534 : RootedObject promiseObj(cx, promise);
2185 267 : if (promise->compartment() != cx->compartment()) {
2186 0 : if (!cx->compartment()->wrap(cx, &promiseObj))
2187 0 : return false;
2188 : }
2189 :
2190 534 : RootedObject resultPromise(cx);
2191 534 : RootedObject resolve(cx);
2192 534 : RootedObject reject(cx);
2193 :
2194 267 : if (createDependent) {
2195 : // Step 3.
2196 534 : RootedValue ctorVal(cx);
2197 267 : if (!SpeciesConstructor(cx, promiseObj, JSProto_Promise, &ctorVal))
2198 0 : return false;
2199 534 : RootedObject C(cx, &ctorVal.toObject());
2200 :
2201 : // Step 4.
2202 267 : if (!NewPromiseCapability(cx, C, &resultPromise, &resolve, &reject, true))
2203 0 : return false;
2204 : }
2205 :
2206 : // Step 5.
2207 267 : if (!PerformPromiseThen(cx, promise, onFulfilled, onRejected, resultPromise, resolve, reject))
2208 0 : return false;
2209 :
2210 267 : dependent.set(resultPromise);
2211 267 : return true;
2212 : }
2213 :
2214 : static MOZ_MUST_USE bool PerformPromiseThenWithReaction(JSContext* cx,
2215 : Handle<PromiseObject*> promise,
2216 : Handle<PromiseReactionRecord*> reaction);
2217 :
2218 : // Some async/await functions are implemented here instead of
2219 : // js/src/builtin/AsyncFunction.cpp, to call Promise internal functions.
2220 :
2221 : // Async Functions proposal 1.1.8 and 1.2.14 step 1.
2222 : MOZ_MUST_USE PromiseObject*
2223 52 : js::CreatePromiseObjectForAsync(JSContext* cx, HandleValue generatorVal)
2224 : {
2225 : // Step 1.
2226 104 : Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
2227 52 : if (!promise)
2228 0 : return nullptr;
2229 :
2230 52 : AddPromiseFlags(*promise, PROMISE_FLAG_ASYNC);
2231 52 : promise->setFixedSlot(PromiseSlot_AwaitGenerator, generatorVal);
2232 52 : return promise;
2233 : }
2234 :
2235 : // Async Functions proposal 2.2 steps 3.f, 3.g.
2236 : MOZ_MUST_USE bool
2237 0 : js::AsyncFunctionThrown(JSContext* cx, Handle<PromiseObject*> resultPromise)
2238 : {
2239 : // Step 3.f.
2240 0 : RootedValue exc(cx);
2241 0 : if (!MaybeGetAndClearException(cx, &exc))
2242 0 : return false;
2243 :
2244 0 : if (!RejectMaybeWrappedPromise(cx, resultPromise, exc))
2245 0 : return false;
2246 :
2247 : // Step 3.g.
2248 0 : return true;
2249 : }
2250 :
2251 : // Async Functions proposal 2.2 steps 3.d-e, 3.g.
2252 : MOZ_MUST_USE bool
2253 33 : js::AsyncFunctionReturned(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value)
2254 : {
2255 : // Steps 3.d-e.
2256 33 : if (!ResolvePromiseInternal(cx, resultPromise, value))
2257 0 : return false;
2258 :
2259 : // Step 3.g.
2260 33 : return true;
2261 : }
2262 :
2263 : // Async Functions proposal 2.3 steps 2-8.
2264 : MOZ_MUST_USE bool
2265 71 : js::AsyncFunctionAwait(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value)
2266 : {
2267 : // Step 2.
2268 142 : Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
2269 71 : if (!promise)
2270 0 : return false;
2271 :
2272 : // Steps 3.
2273 71 : if (!ResolvePromiseInternal(cx, promise, value))
2274 0 : return false;
2275 :
2276 : // Steps 4-5.
2277 142 : RootedValue onFulfilled(cx, Int32Value(PromiseHandlerAsyncFunctionAwaitFulfilled));
2278 142 : RootedValue onRejected(cx, Int32Value(PromiseHandlerAsyncFunctionAwaitRejected));
2279 :
2280 142 : RootedObject incumbentGlobal(cx);
2281 71 : if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal))
2282 0 : return false;
2283 :
2284 : // Steps 6-7.
2285 142 : Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise,
2286 : onFulfilled, onRejected,
2287 : nullptr, nullptr,
2288 142 : incumbentGlobal));
2289 71 : if (!reaction)
2290 0 : return false;
2291 :
2292 71 : reaction->setIsAsyncFunctionAwait();
2293 :
2294 : // Step 8.
2295 71 : return PerformPromiseThenWithReaction(cx, promise, reaction);
2296 : }
2297 :
2298 : // Async Iteration proposal 5.1 steps 2-9.
2299 : MOZ_MUST_USE bool
2300 0 : js::AsyncGeneratorAwait(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
2301 : HandleValue value)
2302 : {
2303 : // Step 2.
2304 0 : Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
2305 0 : if (!promise)
2306 0 : return false;
2307 :
2308 : // Steps 3.
2309 0 : if (!ResolvePromiseInternal(cx, promise, value))
2310 0 : return false;
2311 :
2312 : // Steps 4-5.
2313 0 : RootedValue onFulfilled(cx, Int32Value(PromiseHandlerAsyncGeneratorAwaitFulfilled));
2314 0 : RootedValue onRejected(cx, Int32Value(PromiseHandlerAsyncGeneratorAwaitRejected));
2315 :
2316 0 : RootedObject incumbentGlobal(cx);
2317 0 : if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal))
2318 0 : return false;
2319 :
2320 : // Step 6 (skipped).
2321 :
2322 : // Steps 7-8.
2323 0 : Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, nullptr,
2324 : onFulfilled, onRejected,
2325 : nullptr, nullptr,
2326 0 : incumbentGlobal));
2327 0 : if (!reaction)
2328 0 : return false;
2329 :
2330 0 : reaction->setIsAsyncGeneratorAwait(asyncGenObj);
2331 :
2332 : // Step 9.
2333 0 : return PerformPromiseThenWithReaction(cx, promise, reaction);
2334 : }
2335 :
2336 : // Async Iteration proposal 6.1.3.2.1 %AsyncFromSyncIteratorPrototype%.next
2337 : // Async Iteration proposal 6.1.3.2.2 %AsyncFromSyncIteratorPrototype%.return
2338 : // Async Iteration proposal 6.1.3.2.3 %AsyncFromSyncIteratorPrototype%.throw
2339 : bool
2340 0 : js::AsyncFromSyncIteratorMethod(JSContext* cx, CallArgs& args, CompletionKind completionKind)
2341 : {
2342 : // Step 1.
2343 0 : RootedValue thisVal(cx, args.thisv());
2344 :
2345 : // Step 2.
2346 0 : RootedObject resultPromise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
2347 0 : if (!resultPromise)
2348 0 : return false;
2349 :
2350 : // Step 3.
2351 0 : if (!thisVal.isObject() || !thisVal.toObject().is<AsyncFromSyncIteratorObject>()) {
2352 : // Step 3.a.
2353 0 : RootedValue badGeneratorError(cx);
2354 0 : if (!GetTypeError(cx, JSMSG_NOT_AN_ASYNC_ITERATOR, &badGeneratorError))
2355 0 : return false;
2356 :
2357 : // Step 3.b.
2358 0 : if (!RejectMaybeWrappedPromise(cx, resultPromise, badGeneratorError))
2359 0 : return false;
2360 :
2361 : // Step 3.c.
2362 0 : args.rval().setObject(*resultPromise);
2363 0 : return true;
2364 : }
2365 :
2366 : Rooted<AsyncFromSyncIteratorObject*> asyncIter(
2367 0 : cx, &thisVal.toObject().as<AsyncFromSyncIteratorObject>());
2368 :
2369 : // Step 4.
2370 0 : RootedObject iter(cx, asyncIter->iterator());
2371 :
2372 0 : RootedValue resultVal(cx);
2373 0 : RootedValue func(cx);
2374 0 : if (completionKind == CompletionKind::Normal) {
2375 : // 6.1.3.2.1 steps 5-6 (partially).
2376 0 : if (!GetProperty(cx, iter, iter, cx->names().next, &func))
2377 0 : return AbruptRejectPromise(cx, args, resultPromise, nullptr);
2378 0 : } else if (completionKind == CompletionKind::Return) {
2379 : // 6.1.3.2.2 steps 5-6.
2380 0 : if (!GetProperty(cx, iter, iter, cx->names().return_, &func))
2381 0 : return AbruptRejectPromise(cx, args, resultPromise, nullptr);
2382 :
2383 : // Step 7.
2384 0 : if (func.isNullOrUndefined()) {
2385 : // Step 7.a.
2386 0 : RootedObject resultObj(cx, CreateIterResultObject(cx, args.get(0), true));
2387 0 : if (!resultObj)
2388 0 : return AbruptRejectPromise(cx, args, resultPromise, nullptr);
2389 :
2390 0 : RootedValue resultVal(cx, ObjectValue(*resultObj));
2391 :
2392 : // Step 7.b.
2393 0 : if (!ResolvePromiseInternal(cx, resultPromise, resultVal))
2394 0 : return AbruptRejectPromise(cx, args, resultPromise, nullptr);
2395 :
2396 : // Step 7.c.
2397 0 : args.rval().setObject(*resultPromise);
2398 0 : return true;
2399 : }
2400 : } else {
2401 : // 6.1.3.2.3 steps 5-6.
2402 0 : MOZ_ASSERT(completionKind == CompletionKind::Throw);
2403 0 : if (!GetProperty(cx, iter, iter, cx->names().throw_, &func))
2404 0 : return AbruptRejectPromise(cx, args, resultPromise, nullptr);
2405 :
2406 : // Step 7.
2407 0 : if (func.isNullOrUndefined()) {
2408 : // Step 7.a.
2409 0 : if (!RejectMaybeWrappedPromise(cx, resultPromise, args.get(0)))
2410 0 : return AbruptRejectPromise(cx, args, resultPromise, nullptr);
2411 :
2412 : // Step 7.b.
2413 0 : args.rval().setObject(*resultPromise);
2414 0 : return true;
2415 : }
2416 : }
2417 :
2418 : // 6.1.3.2.1 steps 5-6 (partially).
2419 : // 6.1.3.2.2, 6.1.3.2.3 steps 8-9.
2420 0 : RootedValue iterVal(cx, ObjectValue(*iter));
2421 0 : FixedInvokeArgs<1> args2(cx);
2422 0 : args2[0].set(args.get(0));
2423 0 : if (!js::Call(cx, func, iterVal, args2, &resultVal))
2424 0 : return AbruptRejectPromise(cx, args, resultPromise, nullptr);
2425 :
2426 : // 6.1.3.2.1 steps 5-6 (partially).
2427 : // 6.1.3.2.2, 6.1.3.2.3 steps 10.
2428 0 : if (!resultVal.isObject()) {
2429 : CheckIsObjectKind kind;
2430 0 : switch (completionKind) {
2431 : case CompletionKind::Normal:
2432 0 : kind = CheckIsObjectKind::IteratorNext;
2433 0 : break;
2434 : case CompletionKind::Throw:
2435 0 : kind = CheckIsObjectKind::IteratorThrow;
2436 0 : break;
2437 : case CompletionKind::Return:
2438 0 : kind = CheckIsObjectKind::IteratorReturn;
2439 0 : break;
2440 : }
2441 0 : MOZ_ALWAYS_FALSE(ThrowCheckIsObject(cx, kind));
2442 0 : return AbruptRejectPromise(cx, args, resultPromise, nullptr);
2443 : }
2444 :
2445 0 : RootedObject resultObj(cx, &resultVal.toObject());
2446 :
2447 : // Following step numbers are for 6.1.3.2.1.
2448 : // For 6.1.3.2.2 and 6.1.3.2.3, steps 7-16 corresponds to steps 11-20.
2449 :
2450 : // Steps 7-8.
2451 0 : RootedValue doneVal(cx);
2452 0 : if (!GetProperty(cx, resultObj, resultObj, cx->names().done, &doneVal))
2453 0 : return AbruptRejectPromise(cx, args, resultPromise, nullptr);
2454 0 : bool done = ToBoolean(doneVal);
2455 :
2456 : // Steps 9-10.
2457 0 : RootedValue value(cx);
2458 0 : if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value))
2459 0 : return AbruptRejectPromise(cx, args, resultPromise, nullptr);
2460 :
2461 : // Step 11.
2462 0 : Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
2463 0 : if (!promise)
2464 0 : return false;
2465 :
2466 : // Step 12.
2467 0 : if (!ResolvePromiseInternal(cx, promise, value))
2468 0 : return false;
2469 :
2470 : // Steps 13-14.
2471 0 : RootedValue onFulfilled(cx, Int32Value(done
2472 : ? PromiseHandlerAsyncIteratorValueUnwrapDone
2473 0 : : PromiseHandlerAsyncIteratorValueUnwrapNotDone));
2474 :
2475 0 : RootedObject incumbentGlobal(cx);
2476 0 : if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal))
2477 0 : return false;
2478 :
2479 : // Step 15.
2480 0 : Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise, onFulfilled,
2481 : UndefinedHandleValue,
2482 : nullptr, nullptr,
2483 0 : incumbentGlobal));
2484 0 : if (!reaction)
2485 0 : return false;
2486 :
2487 0 : if (!PerformPromiseThenWithReaction(cx, promise, reaction))
2488 0 : return false;
2489 :
2490 : // Step 16.
2491 0 : args.rval().setObject(*resultPromise);
2492 0 : return true;
2493 : }
2494 :
2495 : // Async Iteration proposal 6.4.3.3.
2496 : MOZ_MUST_USE bool
2497 0 : js::AsyncGeneratorResolve(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
2498 : HandleValue value, bool done)
2499 : {
2500 : // Step 1 (implicit).
2501 :
2502 : // Steps 2-3.
2503 0 : MOZ_ASSERT(!asyncGenObj->isQueueEmpty());
2504 :
2505 : // Step 4.
2506 : Rooted<AsyncGeneratorRequest*> request(
2507 0 : cx, AsyncGeneratorObject::dequeueRequest(cx, asyncGenObj));
2508 0 : if (!request)
2509 0 : return false;
2510 :
2511 : // Step 5.
2512 0 : RootedObject resultPromise(cx, request->promise());
2513 :
2514 : // Step 6.
2515 0 : Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
2516 0 : if (!promise)
2517 0 : return false;
2518 :
2519 : // Step 7.
2520 0 : if (!ResolvePromiseInternal(cx, promise, value))
2521 0 : return false;
2522 :
2523 : // Steps 8-9.
2524 0 : RootedValue onFulfilled(cx, Int32Value(done
2525 : ? PromiseHandlerAsyncIteratorValueUnwrapDone
2526 0 : : PromiseHandlerAsyncIteratorValueUnwrapNotDone));
2527 :
2528 0 : RootedObject incumbentGlobal(cx);
2529 0 : if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal))
2530 0 : return false;
2531 :
2532 : // Step 10.
2533 0 : Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise, onFulfilled,
2534 : UndefinedHandleValue,
2535 : nullptr, nullptr,
2536 0 : incumbentGlobal));
2537 0 : if (!reaction)
2538 0 : return false;
2539 :
2540 0 : if (!PerformPromiseThenWithReaction(cx, promise, reaction))
2541 0 : return false;
2542 :
2543 : // Step 11.
2544 0 : if (!AsyncGeneratorResumeNext(cx, asyncGenObj))
2545 0 : return false;
2546 :
2547 : // Step 12.
2548 0 : return true;
2549 : }
2550 :
2551 : // Async Iteration proposal 6.4.3.4.
2552 : MOZ_MUST_USE bool
2553 0 : js::AsyncGeneratorReject(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
2554 : HandleValue exception)
2555 : {
2556 : // Step 1 (implicit).
2557 :
2558 : // Steps 2-3.
2559 0 : MOZ_ASSERT(!asyncGenObj->isQueueEmpty());
2560 :
2561 : // Step 4.
2562 : Rooted<AsyncGeneratorRequest*> request(
2563 0 : cx, AsyncGeneratorObject::dequeueRequest(cx, asyncGenObj));
2564 0 : if (!request)
2565 0 : return false;
2566 :
2567 : // Step 5.
2568 0 : RootedObject resultPromise(cx, request->promise());
2569 :
2570 : // Step 6.
2571 0 : if (!RejectMaybeWrappedPromise(cx, resultPromise, exception))
2572 0 : return false;
2573 :
2574 : // Step 7.
2575 0 : if (!AsyncGeneratorResumeNext(cx, asyncGenObj))
2576 0 : return false;
2577 :
2578 : // Step 8.
2579 0 : return true;
2580 : }
2581 :
2582 : // Async Iteration proposal 6.4.3.6.
2583 : MOZ_MUST_USE bool
2584 0 : js::AsyncGeneratorEnqueue(JSContext* cx, HandleValue asyncGenVal,
2585 : CompletionKind completionKind, HandleValue completionValue,
2586 : MutableHandleValue result)
2587 : {
2588 : // Step 1 (implicit).
2589 :
2590 : // Step 2.
2591 0 : RootedObject resultPromise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
2592 0 : if (!resultPromise)
2593 0 : return false;
2594 :
2595 : // Step 3.
2596 0 : if (!asyncGenVal.isObject() || !asyncGenVal.toObject().is<AsyncGeneratorObject>()) {
2597 : // Step 3.a.
2598 0 : RootedValue badGeneratorError(cx);
2599 0 : if (!GetTypeError(cx, JSMSG_NOT_AN_ASYNC_GENERATOR, &badGeneratorError))
2600 0 : return false;
2601 :
2602 : // Step 3.b.
2603 0 : if (!RejectMaybeWrappedPromise(cx, resultPromise, badGeneratorError))
2604 0 : return false;
2605 :
2606 : // Step 3.c.
2607 0 : result.setObject(*resultPromise);
2608 0 : return true;
2609 : }
2610 :
2611 : Rooted<AsyncGeneratorObject*> asyncGenObj(
2612 0 : cx, &asyncGenVal.toObject().as<AsyncGeneratorObject>());
2613 :
2614 : // Step 5 (reordered).
2615 : Rooted<AsyncGeneratorRequest*> request(
2616 0 : cx, AsyncGeneratorRequest::create(cx, completionKind, completionValue, resultPromise));
2617 0 : if (!request)
2618 0 : return false;
2619 :
2620 : // Steps 4, 6.
2621 0 : if (!AsyncGeneratorObject::enqueueRequest(cx, asyncGenObj, request))
2622 0 : return false;
2623 :
2624 : // Step 7.
2625 0 : if (!asyncGenObj->isExecuting()) {
2626 : // Step 8.
2627 0 : if (!AsyncGeneratorResumeNext(cx, asyncGenObj))
2628 0 : return false;
2629 : }
2630 :
2631 : // Step 9.
2632 0 : result.setObject(*resultPromise);
2633 0 : return true;
2634 : }
2635 :
2636 : // ES2016, 25.4.5.3.
2637 : bool
2638 267 : js::Promise_then(JSContext* cx, unsigned argc, Value* vp)
2639 : {
2640 267 : CallArgs args = CallArgsFromVp(argc, vp);
2641 :
2642 : // Step 1.
2643 534 : RootedValue promiseVal(cx, args.thisv());
2644 :
2645 534 : RootedValue onFulfilled(cx, args.get(0));
2646 534 : RootedValue onRejected(cx, args.get(1));
2647 :
2648 : // Step 2.
2649 267 : if (!promiseVal.isObject()) {
2650 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
2651 0 : "Receiver of Promise.prototype.then call");
2652 0 : return false;
2653 : }
2654 534 : RootedObject promiseObj(cx, &promiseVal.toObject());
2655 534 : Rooted<PromiseObject*> promise(cx);
2656 :
2657 267 : bool isPromise = promiseObj->is<PromiseObject>();
2658 267 : if (isPromise) {
2659 267 : promise = &promiseObj->as<PromiseObject>();
2660 : } else {
2661 0 : RootedObject unwrappedPromiseObj(cx, CheckedUnwrap(promiseObj));
2662 0 : if (!unwrappedPromiseObj) {
2663 0 : ReportAccessDenied(cx);
2664 0 : return false;
2665 : }
2666 0 : if (!unwrappedPromiseObj->is<PromiseObject>()) {
2667 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
2668 0 : "Promise", "then", "value");
2669 0 : return false;
2670 : }
2671 0 : promise = &unwrappedPromiseObj->as<PromiseObject>();
2672 : }
2673 :
2674 : // Steps 3-5.
2675 534 : RootedObject resultPromise(cx);
2676 267 : if (!OriginalPromiseThen(cx, promise, onFulfilled, onRejected, &resultPromise, true))
2677 0 : return false;
2678 :
2679 267 : args.rval().setObject(*resultPromise);
2680 267 : return true;
2681 : }
2682 :
2683 : // ES2016, 25.4.5.3.1.
2684 : static MOZ_MUST_USE bool
2685 275 : PerformPromiseThen(JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled_,
2686 : HandleValue onRejected_, HandleObject resultPromise,
2687 : HandleObject resolve, HandleObject reject)
2688 : {
2689 : // Step 1 (implicit).
2690 : // Step 2 (implicit).
2691 :
2692 : // Step 3.
2693 550 : RootedValue onFulfilled(cx, onFulfilled_);
2694 275 : if (!IsCallable(onFulfilled))
2695 87 : onFulfilled = Int32Value(PromiseHandlerIdentity);
2696 :
2697 : // Step 4.
2698 550 : RootedValue onRejected(cx, onRejected_);
2699 275 : if (!IsCallable(onRejected))
2700 102 : onRejected = Int32Value(PromiseHandlerThrower);
2701 :
2702 550 : RootedObject incumbentGlobal(cx);
2703 275 : if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal))
2704 0 : return false;
2705 :
2706 : // Step 7.
2707 550 : Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise,
2708 : onFulfilled, onRejected,
2709 : resolve, reject,
2710 550 : incumbentGlobal));
2711 275 : if (!reaction)
2712 0 : return false;
2713 :
2714 275 : return PerformPromiseThenWithReaction(cx, promise, reaction);
2715 : }
2716 :
2717 : static MOZ_MUST_USE bool
2718 346 : PerformPromiseThenWithReaction(JSContext* cx, Handle<PromiseObject*> promise,
2719 : Handle<PromiseReactionRecord*> reaction)
2720 : {
2721 346 : JS::PromiseState state = promise->state();
2722 346 : int32_t flags = promise->getFixedSlot(PromiseSlot_Flags).toInt32();
2723 346 : if (state == JS::PromiseState::Pending) {
2724 : // Steps 5,6 (reordered).
2725 : // Instead of creating separate reaction records for fulfillment and
2726 : // rejection, we create a combined record. All places we use the record
2727 : // can handle that.
2728 315 : if (!AddPromiseReaction(cx, promise, reaction))
2729 0 : return false;
2730 : }
2731 :
2732 : // Steps 8,9.
2733 : else {
2734 : // Step 9.a.
2735 31 : MOZ_ASSERT_IF(state != JS::PromiseState::Fulfilled, state == JS::PromiseState::Rejected);
2736 :
2737 : // Step 8.a. / 9.b.
2738 62 : RootedValue valueOrReason(cx, promise->getFixedSlot(PromiseSlot_ReactionsOrResult));
2739 :
2740 : // We might be operating on a promise from another compartment. In
2741 : // that case, we need to wrap the result/reason value before using it.
2742 31 : if (!cx->compartment()->wrap(cx, &valueOrReason))
2743 0 : return false;
2744 :
2745 : // Step 9.c.
2746 31 : if (state == JS::PromiseState::Rejected && !(flags & PROMISE_FLAG_HANDLED))
2747 0 : cx->runtime()->removeUnhandledRejectedPromise(cx, promise);
2748 :
2749 : // Step 8.b. / 9.d.
2750 31 : if (!EnqueuePromiseReactionJob(cx, reaction, valueOrReason, state))
2751 0 : return false;
2752 : }
2753 :
2754 : // Step 10.
2755 346 : promise->setFixedSlot(PromiseSlot_Flags, Int32Value(flags | PROMISE_FLAG_HANDLED));
2756 :
2757 : // Step 11.
2758 346 : return true;
2759 : }
2760 :
2761 : /**
2762 : * Calls |promise.then| with the provided hooks and adds |blockedPromise| to
2763 : * its list of dependent promises. Used by |Promise.all| and |Promise.race|.
2764 : *
2765 : * If |promise.then| is the original |Promise.prototype.then| function and
2766 : * the call to |promise.then| would use the original |Promise| constructor to
2767 : * create the resulting promise, this function skips the call to |promise.then|
2768 : * and thus creating a new promise that would not be observable by content.
2769 : */
2770 : static MOZ_MUST_USE bool
2771 8 : BlockOnPromise(JSContext* cx, HandleValue promiseVal, HandleObject blockedPromise_,
2772 : HandleValue onFulfilled, HandleValue onRejected)
2773 : {
2774 16 : RootedValue thenVal(cx);
2775 8 : if (!GetProperty(cx, promiseVal, cx->names().then, &thenVal))
2776 0 : return false;
2777 :
2778 16 : RootedObject promiseObj(cx);
2779 8 : if (promiseVal.isObject())
2780 8 : promiseObj = &promiseVal.toObject();
2781 :
2782 8 : if (promiseObj && promiseObj->is<PromiseObject>() && IsNativeFunction(thenVal, Promise_then)) {
2783 : // |promise| is an unwrapped Promise, and |then| is the original
2784 : // |Promise.prototype.then|, inline it here.
2785 : // 25.4.5.3., step 3.
2786 8 : RootedObject PromiseCtor(cx);
2787 8 : if (!GetBuiltinConstructor(cx, JSProto_Promise, &PromiseCtor))
2788 0 : return false;
2789 8 : RootedValue PromiseCtorVal(cx, ObjectValue(*PromiseCtor));
2790 8 : RootedValue CVal(cx);
2791 8 : if (!SpeciesConstructor(cx, promiseObj, PromiseCtorVal, &CVal))
2792 0 : return false;
2793 8 : RootedObject C(cx, &CVal.toObject());
2794 :
2795 8 : RootedObject resultPromise(cx, blockedPromise_);
2796 8 : RootedObject resolveFun(cx);
2797 8 : RootedObject rejectFun(cx);
2798 :
2799 : // By default, the blocked promise is added as an extra entry to the
2800 : // rejected promises list.
2801 8 : bool addToDependent = true;
2802 :
2803 8 : if (C == PromiseCtor) {
2804 8 : addToDependent = false;
2805 : } else {
2806 : // 25.4.5.3., step 4.
2807 0 : if (!NewPromiseCapability(cx, C, &resultPromise, &resolveFun, &rejectFun, true))
2808 0 : return false;
2809 : }
2810 :
2811 : // 25.4.5.3., step 5.
2812 8 : Rooted<PromiseObject*> promise(cx, &promiseObj->as<PromiseObject>());
2813 8 : if (!PerformPromiseThen(cx, promise, onFulfilled, onRejected, resultPromise,
2814 : resolveFun, rejectFun))
2815 : {
2816 0 : return false;
2817 : }
2818 :
2819 8 : if (!addToDependent)
2820 8 : return true;
2821 : } else {
2822 : // Optimization failed, do the normal call.
2823 0 : RootedValue rval(cx);
2824 0 : if (!Call(cx, thenVal, promiseVal, onFulfilled, onRejected, &rval))
2825 0 : return false;
2826 : }
2827 :
2828 : // In case the value to depend on isn't an object at all, there's nothing
2829 : // more to do here: we can only add reactions to Promise objects
2830 : // (potentially after unwrapping them), and non-object values can't be
2831 : // Promise objects. This can happen if Promise.all is called on an object
2832 : // with a `resolve` method that returns primitives.
2833 0 : if (!promiseObj)
2834 0 : return true;
2835 :
2836 : // The object created by the |promise.then| call or the inlined version
2837 : // of it above is visible to content (either because |promise.then| was
2838 : // overridden by content and could leak it, or because a constructor
2839 : // other than the original value of |Promise| was used to create it).
2840 : // To have both that object and |blockedPromise| show up as dependent
2841 : // promises in the debugger, add a dummy reaction to the list of reject
2842 : // reactions that contains |blockedPromise|, but otherwise does nothing.
2843 0 : RootedObject unwrappedPromiseObj(cx, promiseObj);
2844 0 : RootedObject blockedPromise(cx, blockedPromise_);
2845 :
2846 0 : mozilla::Maybe<AutoCompartment> ac;
2847 0 : if (IsProxy(promiseObj)) {
2848 0 : unwrappedPromiseObj = CheckedUnwrap(promiseObj);
2849 0 : if (!unwrappedPromiseObj) {
2850 0 : ReportAccessDenied(cx);
2851 0 : return false;
2852 : }
2853 0 : if (JS_IsDeadWrapper(unwrappedPromiseObj)) {
2854 0 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
2855 0 : return false;
2856 : }
2857 0 : ac.emplace(cx, unwrappedPromiseObj);
2858 0 : if (!cx->compartment()->wrap(cx, &blockedPromise))
2859 0 : return false;
2860 : }
2861 :
2862 : // If the object to depend on isn't a, maybe-wrapped, Promise instance,
2863 : // we ignore it. All this does is lose some small amount of debug
2864 : // information in scenarios that are highly unlikely to occur in useful
2865 : // code.
2866 0 : if (!unwrappedPromiseObj->is<PromiseObject>())
2867 0 : return true;
2868 :
2869 0 : Rooted<PromiseObject*> promise(cx, &unwrappedPromiseObj->as<PromiseObject>());
2870 0 : return AddPromiseReaction(cx, promise, UndefinedHandleValue, UndefinedHandleValue,
2871 0 : blockedPromise, nullptr, nullptr, nullptr);
2872 : }
2873 :
2874 : static MOZ_MUST_USE bool
2875 315 : AddPromiseReaction(JSContext* cx, Handle<PromiseObject*> promise,
2876 : Handle<PromiseReactionRecord*> reaction)
2877 : {
2878 315 : MOZ_RELEASE_ASSERT(reaction->is<PromiseReactionRecord>());
2879 630 : RootedValue reactionVal(cx, ObjectValue(*reaction));
2880 :
2881 : // The code that creates Promise reactions can handle wrapped Promises,
2882 : // unwrapping them as needed. That means that the `promise` and `reaction`
2883 : // objects we have here aren't necessarily from the same compartment. In
2884 : // order to store the reaction on the promise, we have to ensure that it
2885 : // is properly wrapped.
2886 630 : mozilla::Maybe<AutoCompartment> ac;
2887 315 : if (promise->compartment() != cx->compartment()) {
2888 0 : ac.emplace(cx, promise);
2889 0 : if (!cx->compartment()->wrap(cx, &reactionVal))
2890 0 : return false;
2891 : }
2892 :
2893 : // 25.4.5.3.1 steps 7.a,b.
2894 630 : RootedValue reactionsVal(cx, promise->getFixedSlot(PromiseSlot_ReactionsOrResult));
2895 630 : RootedNativeObject reactions(cx);
2896 :
2897 315 : if (reactionsVal.isUndefined()) {
2898 : // If no reactions existed so far, just store the reaction record directly.
2899 275 : promise->setFixedSlot(PromiseSlot_ReactionsOrResult, reactionVal);
2900 275 : return true;
2901 : }
2902 :
2903 80 : RootedObject reactionsObj(cx, &reactionsVal.toObject());
2904 :
2905 : // If only a single reaction exists, it's stored directly instead of in a
2906 : // list. In that case, `reactionsObj` might be a wrapper, which we can
2907 : // always safely unwrap.
2908 40 : if (IsProxy(reactionsObj)) {
2909 0 : reactionsObj = UncheckedUnwrap(reactionsObj);
2910 0 : if (JS_IsDeadWrapper(reactionsObj)) {
2911 0 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
2912 0 : return false;
2913 : }
2914 0 : MOZ_RELEASE_ASSERT(reactionsObj->is<PromiseReactionRecord>());
2915 : }
2916 :
2917 40 : if (reactionsObj->is<PromiseReactionRecord>()) {
2918 : // If a single reaction existed so far, create a list and store the
2919 : // old and the new reaction in it.
2920 40 : reactions = NewDenseFullyAllocatedArray(cx, 2);
2921 40 : if (!reactions)
2922 0 : return false;
2923 40 : if (reactions->ensureDenseElements(cx, 0, 2) != DenseElementResult::Success)
2924 0 : return false;
2925 :
2926 40 : reactions->setDenseElement(0, reactionsVal);
2927 40 : reactions->setDenseElement(1, reactionVal);
2928 :
2929 40 : promise->setFixedSlot(PromiseSlot_ReactionsOrResult, ObjectValue(*reactions));
2930 : } else {
2931 : // Otherwise, just store the new reaction.
2932 0 : MOZ_RELEASE_ASSERT(reactionsObj->is<NativeObject>());
2933 0 : reactions = &reactionsObj->as<NativeObject>();
2934 0 : uint32_t len = reactions->getDenseInitializedLength();
2935 0 : if (reactions->ensureDenseElements(cx, 0, len + 1) != DenseElementResult::Success)
2936 0 : return false;
2937 0 : reactions->setDenseElement(len, reactionVal);
2938 : }
2939 :
2940 40 : return true;
2941 : }
2942 :
2943 : static MOZ_MUST_USE bool
2944 0 : AddPromiseReaction(JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled,
2945 : HandleValue onRejected, HandleObject dependentPromise,
2946 : HandleObject resolve, HandleObject reject, HandleObject incumbentGlobal)
2947 : {
2948 0 : if (promise->state() != JS::PromiseState::Pending)
2949 0 : return true;
2950 :
2951 0 : Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, dependentPromise,
2952 : onFulfilled, onRejected,
2953 : resolve, reject,
2954 0 : incumbentGlobal));
2955 0 : if (!reaction)
2956 0 : return false;
2957 0 : return AddPromiseReaction(cx, promise, reaction);
2958 : }
2959 :
2960 : namespace {
2961 : // Generator used by PromiseObject::getID.
2962 : mozilla::Atomic<uint64_t> gIDGenerator(0);
2963 : } // namespace
2964 :
2965 : double
2966 0 : PromiseObject::lifetime()
2967 : {
2968 0 : return MillisecondsSinceStartup() - allocationTime();
2969 : }
2970 :
2971 : uint64_t
2972 0 : PromiseObject::getID()
2973 : {
2974 0 : Value idVal(getFixedSlot(PromiseSlot_Id));
2975 0 : if (idVal.isUndefined()) {
2976 0 : idVal.setDouble(++gIDGenerator);
2977 0 : setFixedSlot(PromiseSlot_Id, idVal);
2978 : }
2979 0 : return uint64_t(idVal.toNumber());
2980 : }
2981 :
2982 : /**
2983 : * Returns all promises that directly depend on this one. That means those
2984 : * created by calling `then` on this promise, or the promise returned by
2985 : * `Promise.all(iterable)` or `Promise.race(iterable)`, with this promise
2986 : * being a member of the passed-in `iterable`.
2987 : *
2988 : * Per spec, we should have separate lists of reaction records for the
2989 : * fulfill and reject cases. As an optimization, we have only one of those,
2990 : * containing the required data for both cases. So we just walk that list
2991 : * and extract the dependent promises from all reaction records.
2992 : */
2993 : bool
2994 0 : PromiseObject::dependentPromises(JSContext* cx, MutableHandle<GCVector<Value>> values)
2995 : {
2996 0 : if (state() != JS::PromiseState::Pending)
2997 0 : return true;
2998 :
2999 0 : RootedValue reactionsVal(cx, getFixedSlot(PromiseSlot_ReactionsOrResult));
3000 :
3001 : // If no reactions are pending, we don't have list and are done.
3002 0 : if (reactionsVal.isNullOrUndefined())
3003 0 : return true;
3004 :
3005 0 : RootedNativeObject reactions(cx, &reactionsVal.toObject().as<NativeObject>());
3006 :
3007 : // If only a single reaction is pending, it's stored directly.
3008 0 : if (reactions->is<PromiseReactionRecord>()) {
3009 : // Not all reactions have a Promise on them.
3010 0 : RootedObject promiseObj(cx, reactions->as<PromiseReactionRecord>().promise());
3011 0 : if (!promiseObj)
3012 0 : return true;
3013 :
3014 0 : if (!values.growBy(1))
3015 0 : return false;
3016 :
3017 0 : values[0].setObject(*promiseObj);
3018 0 : return true;
3019 : }
3020 :
3021 0 : uint32_t len = reactions->getDenseInitializedLength();
3022 0 : MOZ_ASSERT(len >= 2);
3023 :
3024 0 : size_t valuesIndex = 0;
3025 0 : Rooted<PromiseReactionRecord*> reaction(cx);
3026 0 : for (size_t i = 0; i < len; i++) {
3027 0 : reaction = &reactions->getDenseElement(i).toObject().as<PromiseReactionRecord>();
3028 :
3029 : // Not all reactions have a Promise on them.
3030 0 : RootedObject promiseObj(cx, reaction->promise());
3031 0 : if (!promiseObj)
3032 0 : continue;
3033 0 : if (!values.growBy(1))
3034 0 : return false;
3035 :
3036 0 : values[valuesIndex++].setObject(*promiseObj);
3037 : }
3038 :
3039 0 : return true;
3040 : }
3041 :
3042 : /* static */ bool
3043 2 : PromiseObject::resolve(JSContext* cx, Handle<PromiseObject*> promise, HandleValue resolutionValue)
3044 : {
3045 2 : MOZ_ASSERT(!PromiseHasAnyFlag(*promise, PROMISE_FLAG_ASYNC));
3046 2 : if (promise->state() != JS::PromiseState::Pending)
3047 0 : return true;
3048 :
3049 2 : if (PromiseHasAnyFlag(*promise, PROMISE_FLAG_DEFAULT_RESOLVE_FUNCTION))
3050 2 : return ResolvePromiseInternal(cx, promise, resolutionValue);
3051 :
3052 0 : RootedObject resolveFun(cx, GetResolveFunctionFromPromise(promise));
3053 0 : RootedValue funVal(cx, ObjectValue(*resolveFun));
3054 :
3055 : // For xray'd Promises, the resolve fun may have been created in another
3056 : // compartment. For the call below to work in that case, wrap the
3057 : // function into the current compartment.
3058 0 : if (!cx->compartment()->wrap(cx, &funVal))
3059 0 : return false;
3060 :
3061 0 : FixedInvokeArgs<1> args(cx);
3062 0 : args[0].set(resolutionValue);
3063 :
3064 0 : RootedValue dummy(cx);
3065 0 : return Call(cx, funVal, UndefinedHandleValue, args, &dummy);
3066 : }
3067 :
3068 : /* static */ bool
3069 0 : PromiseObject::reject(JSContext* cx, Handle<PromiseObject*> promise, HandleValue rejectionValue)
3070 : {
3071 0 : MOZ_ASSERT(!PromiseHasAnyFlag(*promise, PROMISE_FLAG_ASYNC));
3072 0 : if (promise->state() != JS::PromiseState::Pending)
3073 0 : return true;
3074 :
3075 0 : if (PromiseHasAnyFlag(*promise, PROMISE_FLAG_DEFAULT_REJECT_FUNCTION))
3076 0 : return ResolvePromise(cx, promise, rejectionValue, JS::PromiseState::Rejected);
3077 :
3078 0 : RootedValue funVal(cx, promise->getFixedSlot(PromiseSlot_RejectFunction));
3079 0 : MOZ_ASSERT(IsCallable(funVal));
3080 :
3081 0 : FixedInvokeArgs<1> args(cx);
3082 0 : args[0].set(rejectionValue);
3083 :
3084 0 : RootedValue dummy(cx);
3085 0 : return Call(cx, funVal, UndefinedHandleValue, args, &dummy);
3086 : }
3087 :
3088 : /* static */ void
3089 231 : PromiseObject::onSettled(JSContext* cx, Handle<PromiseObject*> promise)
3090 : {
3091 462 : RootedObject stack(cx);
3092 231 : if (cx->options().asyncStack() || cx->compartment()->isDebuggee()) {
3093 231 : if (!JS::CaptureCurrentStack(cx, &stack, JS::StackCapture(JS::AllFrames()))) {
3094 0 : cx->clearPendingException();
3095 0 : return;
3096 : }
3097 : }
3098 231 : promise->setFixedSlot(PromiseSlot_ResolutionSite, ObjectOrNullValue(stack));
3099 231 : promise->setFixedSlot(PromiseSlot_ResolutionTime, DoubleValue(MillisecondsSinceStartup()));
3100 :
3101 231 : if (promise->state() == JS::PromiseState::Rejected && promise->isUnhandled())
3102 0 : cx->runtime()->addUnhandledRejectedPromise(cx, promise);
3103 :
3104 231 : JS::dbg::onPromiseSettled(cx, promise);
3105 : }
3106 :
3107 0 : PromiseTask::PromiseTask(JSContext* cx, Handle<PromiseObject*> promise)
3108 0 : : runtime_(cx->runtime()),
3109 0 : promise_(cx, promise)
3110 0 : {}
3111 :
3112 0 : PromiseTask::~PromiseTask()
3113 : {
3114 0 : MOZ_ASSERT(CurrentThreadCanAccessZone(promise_->zone()));
3115 0 : }
3116 :
3117 : void
3118 0 : PromiseTask::finish(JSContext* cx)
3119 : {
3120 0 : MOZ_ASSERT(cx->runtime() == runtime_);
3121 : {
3122 : // We can't leave a pending exception when returning to the caller so do
3123 : // the same thing as Gecko, which is to ignore the error. This should
3124 : // only happen due to OOM or interruption.
3125 0 : AutoCompartment ac(cx, promise_);
3126 0 : if (!finishPromise(cx, promise_))
3127 0 : cx->clearPendingException();
3128 : }
3129 0 : js_delete(this);
3130 0 : }
3131 :
3132 : void
3133 0 : PromiseTask::cancel(JSContext* cx)
3134 : {
3135 0 : MOZ_ASSERT(cx->runtime() == runtime_);
3136 0 : js_delete(this);
3137 0 : }
3138 :
3139 : bool
3140 0 : PromiseTask::executeAndFinish(JSContext* cx)
3141 : {
3142 0 : MOZ_ASSERT(!CanUseExtraThreads());
3143 0 : execute();
3144 0 : return finishPromise(cx, promise_);
3145 : }
3146 :
3147 : static JSObject*
3148 46 : CreatePromisePrototype(JSContext* cx, JSProtoKey key)
3149 : {
3150 46 : return GlobalObject::createBlankPrototype(cx, cx->global(), &PromiseObject::protoClass_);
3151 : }
3152 :
3153 : static const JSFunctionSpec promise_methods[] = {
3154 : JS_SELF_HOSTED_FN("catch", "Promise_catch", 1, 0),
3155 : JS_FN("then", Promise_then, 2, 0),
3156 : JS_FS_END
3157 : };
3158 :
3159 : static const JSPropertySpec promise_properties[] = {
3160 : JS_STRING_SYM_PS(toStringTag, "Promise", JSPROP_READONLY),
3161 : JS_PS_END
3162 : };
3163 :
3164 : static const JSFunctionSpec promise_static_methods[] = {
3165 : JS_FN("all", Promise_static_all, 1, 0),
3166 : JS_FN("race", Promise_static_race, 1, 0),
3167 : JS_FN("reject", Promise_reject, 1, 0),
3168 : JS_FN("resolve", Promise_static_resolve, 1, 0),
3169 : JS_FS_END
3170 : };
3171 :
3172 : static const JSPropertySpec promise_static_properties[] = {
3173 : JS_SELF_HOSTED_SYM_GET(species, "Promise_static_get_species", 0),
3174 : JS_PS_END
3175 : };
3176 :
3177 : static const ClassSpec PromiseObjectClassSpec = {
3178 : GenericCreateConstructor<PromiseConstructor, 1, gc::AllocKind::FUNCTION>,
3179 : CreatePromisePrototype,
3180 : promise_static_methods,
3181 : promise_static_properties,
3182 : promise_methods,
3183 : promise_properties
3184 : };
3185 :
3186 : const Class PromiseObject::class_ = {
3187 : "Promise",
3188 : JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_Promise) |
3189 : JSCLASS_HAS_XRAYED_CONSTRUCTOR,
3190 : JS_NULL_CLASS_OPS,
3191 : &PromiseObjectClassSpec
3192 : };
3193 :
3194 : const Class PromiseObject::protoClass_ = {
3195 : "PromiseProto",
3196 : JSCLASS_HAS_CACHED_PROTO(JSProto_Promise),
3197 : JS_NULL_CLASS_OPS,
3198 : &PromiseObjectClassSpec
3199 : };
|