LCOV - code coverage report
Current view: top level - js/src/builtin - Promise.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 713 1374 51.9 %
Date: 2017-07-14 16:53:18 Functions: 62 91 68.1 %
Legend: Lines: hit not hit

          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             : };

Generated by: LCOV version 1.13