LCOV - code coverage report
Current view: top level - js/src/builtin - Promise.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 441 1493 29.5 %
Date: 2018-08-07 16:35:00 Functions: 0 0 -
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 "jsexn.h"
      14             : #include "jsfriendapi.h"
      15             : 
      16             : #include "gc/Heap.h"
      17             : #include "js/Debug.h"
      18             : #include "vm/AsyncFunction.h"
      19             : #include "vm/AsyncIteration.h"
      20             : #include "vm/Debugger.h"
      21             : #include "vm/Iteration.h"
      22             : #include "vm/JSContext.h"
      23             : 
      24             : #include "vm/Compartment-inl.h"
      25             : #include "vm/Debugger-inl.h"
      26             : #include "vm/JSObject-inl.h"
      27             : #include "vm/NativeObject-inl.h"
      28             : 
      29             : using namespace js;
      30             : 
      31             : static double
      32        8513 : MillisecondsSinceStartup()
      33             : {
      34           0 :     auto now = mozilla::TimeStamp::Now();
      35       17026 :     return (now - mozilla::TimeStamp::ProcessCreation()).ToMilliseconds();
      36             : }
      37             : 
      38             : enum PromiseHandler {
      39             :     PromiseHandlerIdentity = 0,
      40             :     PromiseHandlerThrower,
      41             : 
      42             :     // ES 2018 draft 25.5.5.4-5.
      43             :     PromiseHandlerAsyncFunctionAwaitedFulfilled,
      44             :     PromiseHandlerAsyncFunctionAwaitedRejected,
      45             : 
      46             :     // Async Iteration proposal 4.1.
      47             :     PromiseHandlerAsyncGeneratorAwaitedFulfilled,
      48             :     PromiseHandlerAsyncGeneratorAwaitedRejected,
      49             : 
      50             :     // Async Iteration proposal 11.4.3.5.1-2.
      51             :     PromiseHandlerAsyncGeneratorResumeNextReturnFulfilled,
      52             :     PromiseHandlerAsyncGeneratorResumeNextReturnRejected,
      53             : 
      54             :     // Async Iteration proposal 11.4.3.7 steps 8.c-e.
      55             :     PromiseHandlerAsyncGeneratorYieldReturnAwaitedFulfilled,
      56             :     PromiseHandlerAsyncGeneratorYieldReturnAwaitedRejected,
      57             : 
      58             :     // Async Iteration proposal 11.1.3.2.5.
      59             :     // Async-from-Sync iterator handlers take the resolved value and create new
      60             :     // iterator objects.  To do so it needs to forward whether the iterator is
      61             :     // done. In spec, this is achieved via the [[Done]] internal slot. We
      62             :     // enumerate both true and false cases here.
      63             :     PromiseHandlerAsyncFromSyncIteratorValueUnwrapDone,
      64             :     PromiseHandlerAsyncFromSyncIteratorValueUnwrapNotDone,
      65             : };
      66             : 
      67             : enum ResolutionMode {
      68             :     ResolveMode,
      69             :     RejectMode
      70             : };
      71             : 
      72             : enum ResolveFunctionSlots {
      73             :     ResolveFunctionSlot_Promise = 0,
      74             :     ResolveFunctionSlot_RejectFunction,
      75             : };
      76             : 
      77             : enum RejectFunctionSlots {
      78             :     RejectFunctionSlot_Promise = 0,
      79             :     RejectFunctionSlot_ResolveFunction,
      80             : };
      81             : 
      82             : enum PromiseAllResolveElementFunctionSlots {
      83             :     PromiseAllResolveElementFunctionSlot_Data = 0,
      84             :     PromiseAllResolveElementFunctionSlot_ElementIndex,
      85             : };
      86             : 
      87             : enum ReactionJobSlots {
      88             :     ReactionJobSlot_ReactionRecord = 0,
      89             : };
      90             : 
      91             : enum ThenableJobSlots {
      92             :     ThenableJobSlot_Handler = 0,
      93             :     ThenableJobSlot_JobData,
      94             : };
      95             : 
      96             : enum ThenableJobDataIndices {
      97             :     ThenableJobDataIndex_Promise = 0,
      98             :     ThenableJobDataIndex_Thenable,
      99             :     ThenableJobDataLength,
     100             : };
     101             : 
     102             : enum PromiseAllDataHolderSlots {
     103             :     PromiseAllDataHolderSlot_Promise = 0,
     104             :     PromiseAllDataHolderSlot_RemainingElements,
     105             :     PromiseAllDataHolderSlot_ValuesArray,
     106             :     PromiseAllDataHolderSlot_ResolveFunction,
     107             :     PromiseAllDataHolderSlots,
     108             : };
     109             : 
     110             : class PromiseAllDataHolder : public NativeObject
     111             : {
     112             :   public:
     113             :     static const Class class_;
     114          74 :     JSObject* promiseObj() { return &getFixedSlot(PromiseAllDataHolderSlot_Promise).toObject(); }
     115             :     JSObject* resolveObj() {
     116          74 :         return &getFixedSlot(PromiseAllDataHolderSlot_ResolveFunction).toObject();
     117             :     }
     118         229 :     Value valuesArray() { return getFixedSlot(PromiseAllDataHolderSlot_ValuesArray); }
     119             :     int32_t remainingCount() {
     120             :         return getFixedSlot(PromiseAllDataHolderSlot_RemainingElements).toInt32();
     121             :     }
     122           0 :     int32_t increaseRemainingCount() {
     123           0 :         int32_t remainingCount = getFixedSlot(PromiseAllDataHolderSlot_RemainingElements).toInt32();
     124           0 :         remainingCount++;
     125           0 :         setFixedSlot(PromiseAllDataHolderSlot_RemainingElements, Int32Value(remainingCount));
     126         230 :         return remainingCount;
     127             :     }
     128           0 :     int32_t decreaseRemainingCount() {
     129           0 :         int32_t remainingCount = getFixedSlot(PromiseAllDataHolderSlot_RemainingElements).toInt32();
     130           0 :         remainingCount--;
     131           0 :         setFixedSlot(PromiseAllDataHolderSlot_RemainingElements, Int32Value(remainingCount));
     132         314 :         return remainingCount;
     133             :     }
     134             : };
     135             : 
     136             : const Class PromiseAllDataHolder::class_ = {
     137             :     "PromiseAllDataHolder",
     138             :     JSCLASS_HAS_RESERVED_SLOTS(PromiseAllDataHolderSlots)
     139             : };
     140             : 
     141             : static PromiseAllDataHolder*
     142          85 : NewPromiseAllDataHolder(JSContext* cx, HandleObject resultPromise, HandleValue valuesArray,
     143             :                         HandleObject resolve)
     144             : {
     145           0 :     Rooted<PromiseAllDataHolder*> dataHolder(cx, NewObjectWithClassProto<PromiseAllDataHolder>(cx));
     146          85 :     if (!dataHolder)
     147             :         return nullptr;
     148             : 
     149           0 :     assertSameCompartment(cx, resultPromise);
     150           0 :     assertSameCompartment(cx, valuesArray);
     151          85 :     assertSameCompartment(cx, resolve);
     152             : 
     153           0 :     dataHolder->setFixedSlot(PromiseAllDataHolderSlot_Promise, ObjectValue(*resultPromise));
     154           0 :     dataHolder->setFixedSlot(PromiseAllDataHolderSlot_RemainingElements, Int32Value(1));
     155           0 :     dataHolder->setFixedSlot(PromiseAllDataHolderSlot_ValuesArray, valuesArray);
     156           0 :     dataHolder->setFixedSlot(PromiseAllDataHolderSlot_ResolveFunction, ObjectValue(*resolve));
     157          85 :     return dataHolder;
     158             : }
     159             : 
     160             : namespace {
     161             : // Generator used by PromiseObject::getID.
     162             : mozilla::Atomic<uint64_t> gIDGenerator(0);
     163             : } // namespace
     164             : 
     165             : static MOZ_ALWAYS_INLINE bool
     166        8513 : ShouldCaptureDebugInfo(JSContext* cx)
     167             : {
     168       17026 :     return cx->options().asyncStack() || cx->realm()->isDebuggee();
     169             : }
     170             : 
     171             : class PromiseDebugInfo : public NativeObject
     172             : {
     173             :   private:
     174             :     enum Slots {
     175             :         Slot_AllocationSite,
     176             :         Slot_ResolutionSite,
     177             :         Slot_AllocationTime,
     178             :         Slot_ResolutionTime,
     179             :         Slot_Id,
     180             :         SlotCount
     181             :     };
     182             : 
     183             :   public:
     184             :     static const Class class_;
     185           0 :     static PromiseDebugInfo* create(JSContext* cx, Handle<PromiseObject*> promise) {
     186           0 :         Rooted<PromiseDebugInfo*> debugInfo(cx, NewObjectWithClassProto<PromiseDebugInfo>(cx));
     187        4410 :         if (!debugInfo)
     188             :             return nullptr;
     189             : 
     190           0 :         RootedObject stack(cx);
     191       13230 :         if (!JS::CaptureCurrentStack(cx, &stack, JS::StackCapture(JS::AllFrames())))
     192             :             return nullptr;
     193           0 :         debugInfo->setFixedSlot(Slot_AllocationSite, ObjectOrNullValue(stack));
     194           0 :         debugInfo->setFixedSlot(Slot_ResolutionSite, NullValue());
     195           0 :         debugInfo->setFixedSlot(Slot_AllocationTime, DoubleValue(MillisecondsSinceStartup()));
     196           0 :         debugInfo->setFixedSlot(Slot_ResolutionTime, NumberValue(0));
     197       13230 :         promise->setFixedSlot(PromiseSlot_DebugInfo, ObjectValue(*debugInfo));
     198             : 
     199        4410 :         return debugInfo;
     200             :     }
     201             : 
     202           0 :     static PromiseDebugInfo* FromPromise(PromiseObject* promise) {
     203           0 :         Value val = promise->getFixedSlot(PromiseSlot_DebugInfo);
     204           0 :         if (val.isObject())
     205       10143 :             return &val.toObject().as<PromiseDebugInfo>();
     206             :         return nullptr;
     207             :     }
     208             : 
     209             :     /**
     210             :      * Returns the given PromiseObject's process-unique ID.
     211             :      * The ID is lazily assigned when first queried, and then either stored
     212             :      * in the DebugInfo slot if no debug info was recorded for this Promise,
     213             :      * or in the Id slot of the DebugInfo object.
     214             :      */
     215           0 :     static uint64_t id(PromiseObject* promise) {
     216           0 :         Value idVal(promise->getFixedSlot(PromiseSlot_DebugInfo));
     217           0 :         if (idVal.isUndefined()) {
     218           0 :             idVal.setDouble(++gIDGenerator);
     219           0 :             promise->setFixedSlot(PromiseSlot_DebugInfo, idVal);
     220           0 :         } else if (idVal.isObject()) {
     221           0 :             PromiseDebugInfo* debugInfo = FromPromise(promise);
     222           0 :             idVal = debugInfo->getFixedSlot(Slot_Id);
     223           0 :             if (idVal.isUndefined()) {
     224           0 :                 idVal.setDouble(++gIDGenerator);
     225           0 :                 debugInfo->setFixedSlot(Slot_Id, idVal);
     226             :             }
     227             :         }
     228           0 :         return uint64_t(idVal.toNumber());
     229             :     }
     230             : 
     231           0 :     double allocationTime() { return getFixedSlot(Slot_AllocationTime).toNumber(); }
     232           0 :     double resolutionTime() { return getFixedSlot(Slot_ResolutionTime).toNumber(); }
     233           0 :     JSObject* allocationSite() { return getFixedSlot(Slot_AllocationSite).toObjectOrNull(); }
     234           0 :     JSObject* resolutionSite() { return getFixedSlot(Slot_ResolutionSite).toObjectOrNull(); }
     235             : 
     236           0 :     static void setResolutionInfo(JSContext* cx, Handle<PromiseObject*> promise) {
     237           0 :         if (!ShouldCaptureDebugInfo(cx))
     238           0 :             return;
     239             : 
     240             :         // If async stacks weren't enabled and the Promise's global wasn't a
     241             :         // debuggee when the Promise was created, we won't have a debugInfo
     242             :         // object. We still want to capture the resolution stack, so we
     243             :         // create the object now and change it's slots' values around a bit.
     244           0 :         Rooted<PromiseDebugInfo*> debugInfo(cx, FromPromise(promise));
     245           0 :         if (!debugInfo) {
     246           0 :             RootedValue idVal(cx, promise->getFixedSlot(PromiseSlot_DebugInfo));
     247           0 :             debugInfo = create(cx, promise);
     248           0 :             if (!debugInfo) {
     249           0 :                 cx->clearPendingException();
     250           0 :                 return;
     251             :             }
     252             : 
     253             :             // The current stack was stored in the AllocationSite slot, move
     254             :             // it to ResolutionSite as that's what it really is.
     255           0 :             debugInfo->setFixedSlot(Slot_ResolutionSite,
     256           0 :                                     debugInfo->getFixedSlot(Slot_AllocationSite));
     257           0 :             debugInfo->setFixedSlot(Slot_AllocationSite, NullValue());
     258             : 
     259             :             // There's no good default for a missing AllocationTime, so
     260             :             // instead of resetting that, ensure that it's the same as
     261             :             // ResolutionTime, so that the diff shows as 0, which isn't great,
     262             :             // but bearable.
     263           0 :             debugInfo->setFixedSlot(Slot_ResolutionTime,
     264           0 :                                     debugInfo->getFixedSlot(Slot_AllocationTime));
     265             : 
     266             :             // The Promise's ID might've been queried earlier, in which case
     267             :             // it's stored in the DebugInfo slot. We saved that earlier, so
     268             :             // now we can store it in the right place (or leave it as
     269             :             // undefined if it wasn't ever initialized.)
     270           0 :             debugInfo->setFixedSlot(Slot_Id, idVal);
     271           0 :             return;
     272             :         }
     273             : 
     274           0 :         RootedObject stack(cx);
     275           1 :         if (!JS::CaptureCurrentStack(cx, &stack, JS::StackCapture(JS::AllFrames()))) {
     276           0 :             cx->clearPendingException();
     277           0 :             return;
     278             :         }
     279             : 
     280           0 :         debugInfo->setFixedSlot(Slot_ResolutionSite, ObjectOrNullValue(stack));
     281       12309 :         debugInfo->setFixedSlot(Slot_ResolutionTime, DoubleValue(MillisecondsSinceStartup()));
     282             :     }
     283             : };
     284             : 
     285             : const Class PromiseDebugInfo::class_ = {
     286             :     "PromiseDebugInfo",
     287             :     JSCLASS_HAS_RESERVED_SLOTS(SlotCount)
     288             : };
     289             : 
     290             : double
     291           0 : PromiseObject::allocationTime()
     292             : {
     293           0 :     auto debugInfo = PromiseDebugInfo::FromPromise(this);
     294           0 :     if (debugInfo)
     295           0 :         return debugInfo->allocationTime();
     296             :     return 0;
     297             : }
     298             : 
     299             : double
     300           0 : PromiseObject::resolutionTime()
     301             : {
     302           0 :     auto debugInfo = PromiseDebugInfo::FromPromise(this);
     303           0 :     if (debugInfo)
     304           0 :         return debugInfo->resolutionTime();
     305             :     return 0;
     306             : }
     307             : 
     308             : JSObject*
     309        6040 : PromiseObject::allocationSite()
     310             : {
     311           0 :     auto debugInfo = PromiseDebugInfo::FromPromise(this);
     312           0 :     if (debugInfo)
     313        6040 :         return debugInfo->allocationSite();
     314             :     return nullptr;
     315             : }
     316             : 
     317             : JSObject*
     318           0 : PromiseObject::resolutionSite()
     319             : {
     320           0 :     auto debugInfo = PromiseDebugInfo::FromPromise(this);
     321           0 :     if (debugInfo)
     322           0 :         return debugInfo->resolutionSite();
     323             :     return nullptr;
     324             : }
     325             : 
     326             : /**
     327             :  * Wrapper for GetAndClearException that handles cases where no exception is
     328             :  * pending, but an error occurred. This can be the case if an OOM was
     329             :  * encountered while throwing the error.
     330             :  */
     331             : static bool
     332          20 : MaybeGetAndClearException(JSContext* cx, MutableHandleValue rval)
     333             : {
     334          20 :     if (!cx->isExceptionPending())
     335             :         return false;
     336             : 
     337          20 :     return GetAndClearException(cx, rval);
     338             : }
     339             : 
     340             : static MOZ_MUST_USE bool RunResolutionFunction(JSContext *cx, HandleObject resolutionFun,
     341             :                                                HandleValue result, ResolutionMode mode,
     342             :                                                HandleObject promiseObj);
     343             : 
     344             : // ES2016, 25.4.1.1.1, Steps 1.a-b.
     345             : // Extracting all of this internal spec algorithm into a helper function would
     346             : // be tedious, so the check in step 1 and the entirety of step 2 aren't
     347             : // included.
     348             : static bool
     349           0 : AbruptRejectPromise(JSContext *cx, CallArgs& args, HandleObject promiseObj, HandleObject reject)
     350             : {
     351             :     // Step 1.a.
     352           0 :     RootedValue reason(cx);
     353           0 :     if (!MaybeGetAndClearException(cx, &reason))
     354             :         return false;
     355             : 
     356           0 :     if (!RunResolutionFunction(cx, reject, reason, RejectMode, promiseObj))
     357             :         return false;
     358             : 
     359             :     // Step 1.b.
     360           0 :     args.rval().setObject(*promiseObj);
     361           0 :     return true;
     362             : }
     363             : 
     364             : enum ReactionRecordSlots {
     365             :     ReactionRecordSlot_Promise = 0,
     366             :     ReactionRecordSlot_OnFulfilled,
     367             :     ReactionRecordSlot_OnRejected,
     368             :     ReactionRecordSlot_Resolve,
     369             :     ReactionRecordSlot_Reject,
     370             :     ReactionRecordSlot_IncumbentGlobalObject,
     371             :     ReactionRecordSlot_Flags,
     372             :     ReactionRecordSlot_HandlerArg,
     373             :     ReactionRecordSlot_Generator,
     374             :     ReactionRecordSlots,
     375             : };
     376             : 
     377             : #define REACTION_FLAG_RESOLVED                  0x1
     378             : #define REACTION_FLAG_FULFILLED                 0x2
     379             : #define REACTION_FLAG_IGNORE_DEFAULT_RESOLUTION 0x4
     380             : #define REACTION_FLAG_ASYNC_FUNCTION            0x8
     381             : #define REACTION_FLAG_ASYNC_GENERATOR           0x10
     382             : 
     383             : // ES2016, 25.4.1.2.
     384             : class PromiseReactionRecord : public NativeObject
     385             : {
     386             :   public:
     387             :     static const Class class_;
     388             : 
     389           0 :     JSObject* promise() { return getFixedSlot(ReactionRecordSlot_Promise).toObjectOrNull(); }
     390           0 :     int32_t flags() { return getFixedSlot(ReactionRecordSlot_Flags).toInt32(); }
     391           0 :     JS::PromiseState targetState() {
     392           0 :         int32_t flags = this->flags();
     393       20412 :         if (!(flags & REACTION_FLAG_RESOLVED))
     394             :             return JS::PromiseState::Pending;
     395           0 :         return flags & REACTION_FLAG_FULFILLED
     396       14580 :                ? JS::PromiseState::Fulfilled
     397             :                : JS::PromiseState::Rejected;
     398             :     }
     399           0 :     void setTargetState(JS::PromiseState state) {
     400           0 :         int32_t flags = this->flags();
     401           0 :         MOZ_ASSERT(!(flags & REACTION_FLAG_RESOLVED));
     402           0 :         MOZ_ASSERT(state != JS::PromiseState::Pending, "Can't revert a reaction to pending.");
     403           0 :         flags |= REACTION_FLAG_RESOLVED;
     404           0 :         if (state == JS::PromiseState::Fulfilled)
     405           0 :             flags |= REACTION_FLAG_FULFILLED;
     406           0 :         setFixedSlot(ReactionRecordSlot_Flags, Int32Value(flags));
     407           0 :     }
     408           0 :     void setIsAsyncFunction() {
     409           0 :         int32_t flags = this->flags();
     410           0 :         flags |= REACTION_FLAG_ASYNC_FUNCTION;
     411           0 :         setFixedSlot(ReactionRecordSlot_Flags, Int32Value(flags));
     412           0 :     }
     413           0 :     bool isAsyncFunction() {
     414           0 :         int32_t flags = this->flags();
     415        3950 :         return flags & REACTION_FLAG_ASYNC_FUNCTION;
     416             :     }
     417           0 :     void setIsAsyncGenerator(Handle<AsyncGeneratorObject*> asyncGenObj) {
     418           0 :         int32_t flags = this->flags();
     419           0 :         flags |= REACTION_FLAG_ASYNC_GENERATOR;
     420           0 :         setFixedSlot(ReactionRecordSlot_Flags, Int32Value(flags));
     421             : 
     422           0 :         setFixedSlot(ReactionRecordSlot_Generator, ObjectValue(*asyncGenObj));
     423           0 :     }
     424           0 :     bool isAsyncGenerator() {
     425           0 :         int32_t flags = this->flags();
     426        1882 :         return flags & REACTION_FLAG_ASYNC_GENERATOR;
     427             :     }
     428           0 :     AsyncGeneratorObject* asyncGenerator() {
     429           0 :         MOZ_ASSERT(isAsyncGenerator());
     430           0 :         return &getFixedSlot(ReactionRecordSlot_Generator).toObject()
     431           0 :                                                           .as<AsyncGeneratorObject>();
     432             :     }
     433           0 :     Value handler() {
     434           0 :         MOZ_ASSERT(targetState() != JS::PromiseState::Pending);
     435           0 :         uint32_t slot = targetState() == JS::PromiseState::Fulfilled
     436           0 :                         ? ReactionRecordSlot_OnFulfilled
     437           0 :                         : ReactionRecordSlot_OnRejected;
     438        5832 :         return getFixedSlot(slot);
     439             :     }
     440           0 :     Value handlerArg() {
     441           0 :         MOZ_ASSERT(targetState() != JS::PromiseState::Pending);
     442        2916 :         return getFixedSlot(ReactionRecordSlot_HandlerArg);
     443             :     }
     444           0 :     void setHandlerArg(Value& arg) {
     445           0 :         MOZ_ASSERT(targetState() == JS::PromiseState::Pending);
     446           0 :         setFixedSlot(ReactionRecordSlot_HandlerArg, arg);
     447        2916 :     }
     448             :     JSObject* incumbentGlobalObject() {
     449        2916 :         return getFixedSlot(ReactionRecordSlot_IncumbentGlobalObject).toObjectOrNull();
     450             :     }
     451             : };
     452             : 
     453             : const Class PromiseReactionRecord::class_ = {
     454             :     "PromiseReactionRecord",
     455             :     JSCLASS_HAS_RESERVED_SLOTS(ReactionRecordSlots)
     456             : };
     457             : 
     458             : static void
     459        4905 : AddPromiseFlags(PromiseObject& promise, int32_t flag)
     460             : {
     461           0 :     int32_t flags = promise.getFixedSlot(PromiseSlot_Flags).toInt32();
     462           0 :     promise.setFixedSlot(PromiseSlot_Flags, Int32Value(flags | flag));
     463        4905 : }
     464             : 
     465             : static bool
     466        2051 : PromiseHasAnyFlag(PromiseObject& promise, int32_t flag)
     467             : {
     468        2051 :     return promise.getFixedSlot(PromiseSlot_Flags).toInt32() & flag;
     469             : }
     470             : 
     471             : static bool ResolvePromiseFunction(JSContext* cx, unsigned argc, Value* vp);
     472             : static bool RejectPromiseFunction(JSContext* cx, unsigned argc, Value* vp);
     473             : 
     474             : // ES2016, 25.4.1.3.
     475             : static MOZ_MUST_USE MOZ_ALWAYS_INLINE bool
     476        1690 : CreateResolvingFunctions(JSContext* cx, HandleObject promise,
     477             :                          MutableHandleObject resolveFn,
     478             :                          MutableHandleObject rejectFn)
     479             : {
     480           0 :     HandlePropertyName funName = cx->names().empty;
     481           0 :     resolveFn.set(NewNativeFunction(cx, ResolvePromiseFunction, 1, funName,
     482           0 :                                     gc::AllocKind::FUNCTION_EXTENDED, GenericObject));
     483        1690 :     if (!resolveFn)
     484             :         return false;
     485             : 
     486           0 :     rejectFn.set(NewNativeFunction(cx, RejectPromiseFunction, 1, funName,
     487           0 :                                    gc::AllocKind::FUNCTION_EXTENDED, GenericObject));
     488        1690 :     if (!rejectFn)
     489             :         return false;
     490             : 
     491           0 :     JSFunction* resolveFun = &resolveFn->as<JSFunction>();
     492        1690 :     JSFunction* rejectFun = &rejectFn->as<JSFunction>();
     493             : 
     494           0 :     resolveFun->initExtendedSlot(ResolveFunctionSlot_Promise, ObjectValue(*promise));
     495        3380 :     resolveFun->initExtendedSlot(ResolveFunctionSlot_RejectFunction, ObjectValue(*rejectFun));
     496             : 
     497           0 :     rejectFun->initExtendedSlot(RejectFunctionSlot_Promise, ObjectValue(*promise));
     498        3380 :     rejectFun->initExtendedSlot(RejectFunctionSlot_ResolveFunction, ObjectValue(*resolveFun));
     499             : 
     500        1690 :     return true;
     501             : }
     502             : 
     503             : static void ClearResolutionFunctionSlots(JSFunction* resolutionFun);
     504             : static MOZ_MUST_USE bool RejectMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj,
     505             :                                                    HandleValue reason);
     506             : 
     507             : // ES2016, 25.4.1.3.1.
     508             : static bool
     509          66 : RejectPromiseFunction(JSContext* cx, unsigned argc, Value* vp)
     510             : {
     511          66 :     CallArgs args = CallArgsFromVp(argc, vp);
     512             : 
     513           0 :     RootedFunction reject(cx, &args.callee().as<JSFunction>());
     514         132 :     RootedValue reasonVal(cx, args.get(0));
     515             : 
     516             :     // Steps 1-2.
     517         132 :     RootedValue promiseVal(cx, reject->getExtendedSlot(RejectFunctionSlot_Promise));
     518             : 
     519             :     // Steps 3-4.
     520             :     // If the Promise isn't available anymore, it has been resolved and the
     521             :     // reference to it removed to make it eligible for collection.
     522           0 :     if (promiseVal.isUndefined()) {
     523           0 :         args.rval().setUndefined();
     524           0 :         return true;
     525             :     }
     526             : 
     527             :     // Step 5.
     528             :     // Here, we only remove the Promise reference from the resolution
     529             :     // functions. Actually marking it as fulfilled/rejected happens later.
     530          66 :     ClearResolutionFunctionSlots(reject);
     531             : 
     532         132 :     RootedObject promise(cx, &promiseVal.toObject());
     533             : 
     534             :     // In some cases the Promise reference on the resolution function won't
     535             :     // have been removed during resolution, so we need to check that here,
     536             :     // too.
     537           0 :     if (promise->is<PromiseObject>() &&
     538          66 :         promise->as<PromiseObject>().state() != JS::PromiseState::Pending)
     539             :     {
     540             :         return true;
     541             :     }
     542             : 
     543             :     // Step 6.
     544         132 :     if (!RejectMaybeWrappedPromise(cx, promise, reasonVal))
     545             :         return false;
     546           0 :     args.rval().setUndefined();
     547          66 :     return true;
     548             : }
     549             : 
     550             : static MOZ_MUST_USE bool FulfillMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj,
     551             :                                                     HandleValue value_);
     552             : 
     553             : static MOZ_MUST_USE bool EnqueuePromiseResolveThenableJob(JSContext* cx,
     554             :                                                           HandleValue promiseToResolve,
     555             :                                                           HandleValue thenable,
     556             :                                                           HandleValue thenVal);
     557             : 
     558             : // ES2016, 25.4.1.3.2, steps 6-13.
     559             : static MOZ_MUST_USE bool
     560        5223 : ResolvePromiseInternal(JSContext* cx, HandleObject promise, HandleValue resolutionVal)
     561             : {
     562             :     // Step 7 (reordered).
     563           0 :     if (!resolutionVal.isObject())
     564        2129 :         return FulfillMaybeWrappedPromise(cx, promise, resolutionVal);
     565             : 
     566        6188 :     RootedObject resolution(cx, &resolutionVal.toObject());
     567             : 
     568             :     // Step 6.
     569        3094 :     if (resolution == promise) {
     570             :         // Step 6.a.
     571             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
     572           0 :                                   JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF);
     573           0 :         RootedValue selfResolutionError(cx);
     574           0 :         if (!MaybeGetAndClearException(cx, &selfResolutionError))
     575             :             return false;
     576             : 
     577             :         // Step 6.b.
     578           0 :         return RejectMaybeWrappedPromise(cx, promise, selfResolutionError);
     579             :     }
     580             : 
     581             :     // Step 8.
     582           0 :     RootedValue thenVal(cx);
     583       15470 :     bool status = GetProperty(cx, resolution, resolution, cx->names().then, &thenVal);
     584             : 
     585             :     // Step 9.
     586           0 :     if (!status) {
     587           0 :         RootedValue error(cx);
     588           0 :         if (!MaybeGetAndClearException(cx, &error))
     589             :             return false;
     590             : 
     591           0 :         return RejectMaybeWrappedPromise(cx, promise, error);
     592             :     }
     593             : 
     594             :     // Step 10 (implicit).
     595             : 
     596             :     // Step 11.
     597           0 :     if (!IsCallable(thenVal))
     598        1862 :         return FulfillMaybeWrappedPromise(cx, promise, resolutionVal);
     599             : 
     600             :     // Step 12.
     601           0 :     RootedValue promiseVal(cx, ObjectValue(*promise));
     602        2464 :     if (!EnqueuePromiseResolveThenableJob(cx, promiseVal, resolutionVal, thenVal))
     603             :         return false;
     604             : 
     605             :     // Step 13.
     606        1232 :     return true;
     607             : }
     608             : 
     609             : // ES2016, 25.4.1.3.2.
     610             : static bool
     611        1503 : ResolvePromiseFunction(JSContext* cx, unsigned argc, Value* vp)
     612             : {
     613        1503 :     CallArgs args = CallArgsFromVp(argc, vp);
     614             : 
     615           0 :     RootedFunction resolve(cx, &args.callee().as<JSFunction>());
     616        3006 :     RootedValue resolutionVal(cx, args.get(0));
     617             : 
     618             :     // Steps 3-4 (reordered).
     619             :     // We use the reference to the reject function as a signal for whether
     620             :     // the resolve or reject function was already called, at which point
     621             :     // the references on each of the functions are cleared.
     622           0 :     if (!resolve->getExtendedSlot(ResolveFunctionSlot_RejectFunction).isObject()) {
     623           0 :         args.rval().setUndefined();
     624           0 :         return true;
     625             :     }
     626             : 
     627             :     // Steps 1-2 (reordered).
     628        3006 :     RootedObject promise(cx, &resolve->getExtendedSlot(ResolveFunctionSlot_Promise).toObject());
     629             : 
     630             :     // Step 5.
     631             :     // Here, we only remove the Promise reference from the resolution
     632             :     // functions. Actually marking it as fulfilled/rejected happens later.
     633        1503 :     ClearResolutionFunctionSlots(resolve);
     634             : 
     635             :     // In some cases the Promise reference on the resolution function won't
     636             :     // have been removed during resolution, so we need to check that here,
     637             :     // too.
     638           0 :     if (promise->is<PromiseObject>() &&
     639        1469 :         promise->as<PromiseObject>().state() != JS::PromiseState::Pending)
     640             :     {
     641             :         return true;
     642             :     }
     643             : 
     644             :     // Steps 6-13.
     645        3006 :     if (!ResolvePromiseInternal(cx, promise, resolutionVal))
     646             :         return false;
     647           0 :     args.rval().setUndefined();
     648        1503 :     return true;
     649             : }
     650             : 
     651             : static bool PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp);
     652             : 
     653             : /**
     654             :  * Tells the embedding to enqueue a Promise reaction job, based on
     655             :  * three parameters:
     656             :  * reactionObj - The reaction record.
     657             :  * handlerArg_ - The first and only argument to pass to the handler invoked by
     658             :  *              the job. This will be stored on the reaction record.
     659             :  * targetState - The PromiseState this reaction job targets. This decides
     660             :  *               whether the onFulfilled or onRejected handler is called.
     661             :  */
     662             : MOZ_MUST_USE static bool
     663        2916 : EnqueuePromiseReactionJob(JSContext* cx, HandleObject reactionObj,
     664             :                           HandleValue handlerArg_, JS::PromiseState targetState)
     665             : {
     666             :     // The reaction might have been stored on a Promise from another
     667             :     // compartment, which means it would've been wrapped in a CCW.
     668             :     // To properly handle that case here, unwrap it and enter its
     669             :     // compartment, where the job creation should take place anyway.
     670           0 :     Rooted<PromiseReactionRecord*> reaction(cx);
     671           0 :     RootedValue handlerArg(cx, handlerArg_);
     672           0 :     mozilla::Maybe<AutoRealm> ar;
     673           0 :     if (!IsProxy(reactionObj)) {
     674           0 :         MOZ_RELEASE_ASSERT(reactionObj->is<PromiseReactionRecord>());
     675        5826 :         reaction = &reactionObj->as<PromiseReactionRecord>();
     676             :     } else {
     677           0 :         if (JS_IsDeadWrapper(UncheckedUnwrap(reactionObj))) {
     678           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
     679           0 :             return false;
     680             :         }
     681           0 :         reaction = &UncheckedUnwrap(reactionObj)->as<PromiseReactionRecord>();
     682           0 :         MOZ_RELEASE_ASSERT(reaction->is<PromiseReactionRecord>());
     683           0 :         ar.emplace(cx, reaction);
     684           9 :         if (!reaction->compartment()->wrap(cx, &handlerArg))
     685             :             return false;
     686             :     }
     687             : 
     688             :     // Must not enqueue a reaction job more than once.
     689        2916 :     MOZ_ASSERT(reaction->targetState() == JS::PromiseState::Pending);
     690             : 
     691           0 :     assertSameCompartment(cx, handlerArg);
     692        5832 :     reaction->setHandlerArg(handlerArg.get());
     693             : 
     694        8748 :     RootedValue reactionVal(cx, ObjectValue(*reaction));
     695             : 
     696           0 :     reaction->setTargetState(targetState);
     697        5832 :     RootedValue handler(cx, reaction->handler());
     698             : 
     699             :     // If we have a handler callback, we enter that handler's compartment so
     700             :     // that the promise reaction job function is created in that compartment.
     701             :     // That guarantees that the embedding ends up with the right entry global.
     702             :     // This is relevant for some html APIs like fetch that derive information
     703             :     // from said global.
     704           0 :     mozilla::Maybe<AutoRealm> ar2;
     705           0 :     if (handler.isObject()) {
     706        3390 :         RootedObject handlerObj(cx, &handler.toObject());
     707             : 
     708             :         // The unwrapping has to be unchecked because we specifically want to
     709             :         // be able to use handlers with wrappers that would only allow calls.
     710             :         // E.g., it's ok to have a handler from a chrome compartment in a
     711             :         // reaction to a content compartment's Promise instance.
     712           0 :         handlerObj = UncheckedUnwrap(handlerObj);
     713           0 :         MOZ_ASSERT(handlerObj);
     714        1695 :         ar2.emplace(cx, handlerObj);
     715             : 
     716             :         // We need to wrap the reaction to store it on the job function.
     717           1 :         if (!cx->compartment()->wrap(cx, &reactionVal))
     718           0 :             return false;
     719             :     }
     720             : 
     721             :     // Create the JS function to call when the job is triggered.
     722           0 :     RootedAtom funName(cx, cx->names().empty);
     723           0 :     RootedFunction job(cx, NewNativeFunction(cx, PromiseReactionJob, 0, funName,
     724           0 :                                              gc::AllocKind::FUNCTION_EXTENDED, GenericObject));
     725        2916 :     if (!job)
     726             :         return false;
     727             : 
     728             :     // Store the reaction on the reaction job.
     729        5832 :     job->setExtendedSlot(ReactionJobSlot_ReactionRecord, reactionVal);
     730             : 
     731             :     // When using JS::AddPromiseReactions, no actual promise is created, so we
     732             :     // might not have one here.
     733             :     // Additionally, we might have an object here that isn't an instance of
     734             :     // Promise. This can happen if content overrides the value of
     735             :     // Promise[@@species] (or invokes Promise#then on a Promise subclass
     736             :     // instance with a non-default @@species value on the constructor) with a
     737             :     // function that returns objects that're not Promise (subclass) instances.
     738             :     // In that case, we just pretend we didn't have an object in the first
     739             :     // place.
     740             :     // If after all this we do have an object, wrap it in case we entered the
     741             :     // handler's compartment above, because we should pass objects from a
     742             :     // single compartment to the enqueuePromiseJob callback.
     743           0 :     RootedObject promise(cx, reaction->promise());
     744           0 :     if (promise && promise->is<PromiseObject>()) {
     745        5634 :       if (!cx->compartment()->wrap(cx, &promise))
     746             :           return false;
     747             :     }
     748             : 
     749             :     // Using objectFromIncumbentGlobal, we can derive the incumbent global by
     750             :     // unwrapping and then getting the global. This is very convoluted, but
     751             :     // much better than having to store the original global as a private value
     752             :     // because we couldn't wrap it to store it as a normal JS value.
     753           0 :     RootedObject global(cx);
     754           0 :     RootedObject objectFromIncumbentGlobal(cx, reaction->incumbentGlobalObject());
     755           0 :     if (objectFromIncumbentGlobal) {
     756           0 :         objectFromIncumbentGlobal = CheckedUnwrap(objectFromIncumbentGlobal);
     757           0 :         MOZ_ASSERT(objectFromIncumbentGlobal);
     758        8748 :         global = &objectFromIncumbentGlobal->nonCCWGlobal();
     759             :     }
     760             : 
     761             :     // Note: the global we pass here might be from a different compartment
     762             :     // than job and promise. While it's somewhat unusual to pass objects
     763             :     // from multiple compartments, in this case we specifically need the
     764             :     // global to be unwrapped because wrapping and unwrapping aren't
     765             :     // necessarily symmetric for globals.
     766       11664 :     return cx->runtime()->enqueuePromiseJob(cx, job, promise, global);
     767             : }
     768             : 
     769             : static MOZ_MUST_USE bool TriggerPromiseReactions(JSContext* cx, HandleValue reactionsVal,
     770             :                                                  JS::PromiseState state, HandleValue valueOrReason);
     771             : 
     772             : // ES2016, Commoned-out implementation of 25.4.1.4. and 25.4.1.7.
     773             : static MOZ_MUST_USE bool
     774        4103 : ResolvePromise(JSContext* cx, Handle<PromiseObject*> promise, HandleValue valueOrReason,
     775             :                JS::PromiseState state)
     776             : {
     777             :     // Step 1.
     778           0 :     MOZ_ASSERT(promise->state() == JS::PromiseState::Pending);
     779        4103 :     MOZ_ASSERT(state == JS::PromiseState::Fulfilled || state == JS::PromiseState::Rejected);
     780             : 
     781             :     // Step 2.
     782             :     // We only have one list of reactions for both resolution types. So
     783             :     // instead of getting the right list of reactions, we determine the
     784             :     // resolution type to retrieve the right information from the
     785             :     // reaction records.
     786        8206 :     RootedValue reactionsVal(cx, promise->getFixedSlot(PromiseSlot_ReactionsOrResult));
     787             : 
     788             :     // Steps 3-5.
     789             :     // The same slot is used for the reactions list and the result, so setting
     790             :     // the result also removes the reactions list.
     791        8206 :     promise->setFixedSlot(PromiseSlot_ReactionsOrResult, valueOrReason);
     792             : 
     793             :     // Step 6.
     794           0 :     int32_t flags = promise->getFixedSlot(PromiseSlot_Flags).toInt32();
     795           0 :     flags |= PROMISE_FLAG_RESOLVED;
     796           0 :     if (state == JS::PromiseState::Fulfilled)
     797           0 :         flags |= PROMISE_FLAG_FULFILLED;
     798        8206 :     promise->setFixedSlot(PromiseSlot_Flags, Int32Value(flags));
     799             : 
     800             :     // Also null out the resolve/reject functions so they can be GC'd.
     801        8206 :     promise->setFixedSlot(PromiseSlot_RejectFunction, UndefinedValue());
     802             : 
     803             :     // Now that everything else is done, do the things the debugger needs.
     804             :     // Step 7 of RejectPromise implemented in onSettled.
     805        4103 :     PromiseObject::onSettled(cx, promise);
     806             : 
     807             :     // Step 7 of FulfillPromise.
     808             :     // Step 8 of RejectPromise.
     809           0 :     if (reactionsVal.isObject())
     810        2303 :         return TriggerPromiseReactions(cx, reactionsVal, state, valueOrReason);
     811             : 
     812             :     return true;
     813             : }
     814             : 
     815             : // ES2016, 25.4.1.4.
     816             : static MOZ_MUST_USE bool
     817        3991 : FulfillMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj, HandleValue value_)
     818             : {
     819           0 :     Rooted<PromiseObject*> promise(cx);
     820        7982 :     RootedValue value(cx, value_);
     821             : 
     822           0 :     mozilla::Maybe<AutoRealm> ar;
     823           0 :     if (!IsProxy(promiseObj)) {
     824        7916 :         promise = &promiseObj->as<PromiseObject>();
     825             :     } else {
     826           0 :         if (JS_IsDeadWrapper(UncheckedUnwrap(promiseObj))) {
     827           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
     828           0 :             return false;
     829             :         }
     830           0 :         promise = &UncheckedUnwrap(promiseObj)->as<PromiseObject>();
     831           0 :         ar.emplace(cx, promise);
     832          99 :         if (!promise->compartment()->wrap(cx, &value))
     833             :             return false;
     834             :     }
     835             : 
     836        3991 :     MOZ_ASSERT(promise->state() == JS::PromiseState::Pending);
     837             : 
     838        7982 :     return ResolvePromise(cx, promise, value, JS::PromiseState::Fulfilled);
     839             : }
     840             : 
     841             : static bool GetCapabilitiesExecutor(JSContext* cx, unsigned argc, Value* vp);
     842             : static bool PromiseConstructor(JSContext* cx, unsigned argc, Value* vp);
     843             : static MOZ_MUST_USE PromiseObject* CreatePromiseObjectInternal(JSContext* cx,
     844             :                                                                HandleObject proto = nullptr,
     845             :                                                                bool protoIsWrapped = false,
     846             :                                                                bool informDebugger = true);
     847             : 
     848             : enum GetCapabilitiesExecutorSlots {
     849             :     GetCapabilitiesExecutorSlots_Resolve,
     850             :     GetCapabilitiesExecutorSlots_Reject
     851             : };
     852             : 
     853             : static MOZ_MUST_USE PromiseObject*
     854        3952 : CreatePromiseObjectWithoutResolutionFunctions(JSContext* cx)
     855             : {
     856           0 :     PromiseObject* promise = CreatePromiseObjectInternal(cx);
     857        3952 :     if (!promise)
     858             :         return nullptr;
     859             : 
     860             :     AddPromiseFlags(*promise, PROMISE_FLAG_DEFAULT_RESOLVE_FUNCTION |
     861           0 :                     PROMISE_FLAG_DEFAULT_REJECT_FUNCTION);
     862        3952 :     return promise;
     863             : }
     864             : 
     865             : static MOZ_MUST_USE PromiseObject*
     866          93 : CreatePromiseWithDefaultResolutionFunctions(JSContext* cx, MutableHandleObject resolve,
     867             :                                             MutableHandleObject reject)
     868             : {
     869             :     // ES2016, 25.4.3.1., as if called with GetCapabilitiesExecutor as the
     870             :     // executor argument.
     871             : 
     872             :     // Steps 1-2 (Not applicable).
     873             : 
     874             :     // Steps 3-7.
     875           0 :     Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx));
     876          93 :     if (!promise)
     877             :         return nullptr;
     878             : 
     879             :     // Step 8.
     880          93 :     if (!CreateResolvingFunctions(cx, promise, resolve, reject))
     881             :         return nullptr;
     882             : 
     883         279 :     promise->setFixedSlot(PromiseSlot_RejectFunction, ObjectValue(*reject));
     884             : 
     885             :     // Steps 9-10 (Not applicable).
     886             : 
     887             :     // Step 11.
     888          93 :     return promise;
     889             : }
     890             : 
     891             : // ES2016, 25.4.1.5.
     892             : static MOZ_MUST_USE bool
     893        1933 : NewPromiseCapability(JSContext* cx, HandleObject C, MutableHandleObject promise,
     894             :                      MutableHandleObject resolve, MutableHandleObject reject,
     895             :                      bool canOmitResolutionFunctions)
     896             : {
     897        5799 :     RootedValue cVal(cx, ObjectValue(*C));
     898             : 
     899             :     // Steps 1-2.
     900           0 :     if (!IsConstructor(C)) {
     901           0 :         ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_SEARCH_STACK, cVal, nullptr);
     902           0 :         return false;
     903             :     }
     904             : 
     905             :     // If we'd call the original Promise constructor and know that the
     906             :     // resolve/reject functions won't ever escape to content, we can skip
     907             :     // creating and calling the executor function and instead return a Promise
     908             :     // marked as having default resolve/reject functions.
     909             :     //
     910             :     // This can't be used in Promise.all and Promise.race because we have to
     911             :     // pass the reject (and resolve, in the race case) function to thenables
     912             :     // in the list passed to all/race, which (potentially) means exposing them
     913             :     // to content.
     914             :     //
     915             :     // For Promise.all and Promise.race we can only optimize away the creation
     916             :     // of the GetCapabilitiesExecutor function, and directly allocate the
     917             :     // result promise instead of invoking the Promise constructor.
     918           0 :     if (IsNativeFunction(cVal, PromiseConstructor)) {
     919           0 :         if (canOmitResolutionFunctions)
     920        1835 :             promise.set(CreatePromiseObjectWithoutResolutionFunctions(cx));
     921             :         else
     922           0 :             promise.set(CreatePromiseWithDefaultResolutionFunctions(cx, resolve, reject));
     923        1928 :         if (!promise)
     924             :             return false;
     925        1928 :         return true;
     926             :     }
     927             : 
     928             :     // Step 3 (omitted).
     929             : 
     930             :     // Step 4.
     931           0 :     RootedAtom funName(cx, cx->names().empty);
     932           0 :     RootedFunction executor(cx, NewNativeFunction(cx, GetCapabilitiesExecutor, 2, funName,
     933           0 :                                                   gc::AllocKind::FUNCTION_EXTENDED, GenericObject));
     934           5 :     if (!executor)
     935             :         return false;
     936             : 
     937             :     // Step 5 (omitted).
     938             : 
     939             :     // Step 6.
     940           0 :     FixedConstructArgs<1> cargs(cx);
     941           0 :     cargs[0].setObject(*executor);
     942          10 :     if (!Construct(cx, cVal, cargs, cVal, promise))
     943             :         return false;
     944             : 
     945             :     // Step 7.
     946           0 :     RootedValue resolveVal(cx, executor->getExtendedSlot(GetCapabilitiesExecutorSlots_Resolve));
     947           5 :     if (!IsCallable(resolveVal)) {
     948             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
     949           0 :                                   JSMSG_PROMISE_RESOLVE_FUNCTION_NOT_CALLABLE);
     950           0 :         return false;
     951             :     }
     952             : 
     953             :     // Step 8.
     954           0 :     RootedValue rejectVal(cx, executor->getExtendedSlot(GetCapabilitiesExecutorSlots_Reject));
     955           5 :     if (!IsCallable(rejectVal)) {
     956             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
     957           0 :                                   JSMSG_PROMISE_REJECT_FUNCTION_NOT_CALLABLE);
     958           0 :         return false;
     959             :     }
     960             : 
     961             :     // Step 9 (well, the equivalent for all of promiseCapabilities' fields.)
     962           0 :     resolve.set(&resolveVal.toObject());
     963           5 :     reject.set(&rejectVal.toObject());
     964             : 
     965             :     // Step 10.
     966           5 :     return true;
     967             : }
     968             : 
     969             : // ES2016, 25.4.1.5.1.
     970             : static bool
     971           5 : GetCapabilitiesExecutor(JSContext* cx, unsigned argc, Value* vp)
     972             : {
     973           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     974          10 :     RootedFunction F(cx, &args.callee().as<JSFunction>());
     975             : 
     976             :     // Steps 1-2 (implicit).
     977             : 
     978             :     // Steps 3-4.
     979           0 :     if (!F->getExtendedSlot(GetCapabilitiesExecutorSlots_Resolve).isUndefined() ||
     980          10 :         !F->getExtendedSlot(GetCapabilitiesExecutorSlots_Reject).isUndefined())
     981             :     {
     982             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
     983           0 :                                   JSMSG_PROMISE_CAPABILITY_HAS_SOMETHING_ALREADY);
     984           0 :         return false;
     985             :     }
     986             : 
     987             :     // Step 5.
     988          15 :     F->setExtendedSlot(GetCapabilitiesExecutorSlots_Resolve, args.get(0));
     989             : 
     990             :     // Step 6.
     991          15 :     F->setExtendedSlot(GetCapabilitiesExecutorSlots_Reject, args.get(1));
     992             : 
     993             :     // Step 7.
     994           0 :     args.rval().setUndefined();
     995           5 :     return true;
     996             : }
     997             : 
     998             : // ES2016, 25.4.1.7.
     999             : static MOZ_MUST_USE bool
    1000         112 : RejectMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj, HandleValue reason_)
    1001             : {
    1002           0 :     Rooted<PromiseObject*> promise(cx);
    1003         224 :     RootedValue reason(cx, reason_);
    1004             : 
    1005           0 :     mozilla::Maybe<AutoRealm> ar;
    1006           0 :     if (!IsProxy(promiseObj)) {
    1007         224 :         promise = &promiseObj->as<PromiseObject>();
    1008             :     } else {
    1009           0 :         if (JS_IsDeadWrapper(UncheckedUnwrap(promiseObj))) {
    1010           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
    1011           0 :             return false;
    1012             :         }
    1013           0 :         promise = &UncheckedUnwrap(promiseObj)->as<PromiseObject>();
    1014           0 :         ar.emplace(cx, promise);
    1015             : 
    1016             :         // The rejection reason might've been created in a compartment with higher
    1017             :         // privileges than the Promise's. In that case, object-type rejection
    1018             :         // values might be wrapped into a wrapper that throws whenever the
    1019             :         // Promise's reaction handler wants to do anything useful with it. To
    1020             :         // avoid that situation, we synthesize a generic error that doesn't
    1021             :         // expose any privileged information but can safely be used in the
    1022             :         // rejection handler.
    1023           0 :         if (!promise->compartment()->wrap(cx, &reason))
    1024             :             return false;
    1025           0 :         if (reason.isObject() && !CheckedUnwrap(&reason.toObject())) {
    1026             :             // Report the existing reason, so we don't just drop it on the
    1027             :             // floor.
    1028           0 :             RootedObject realReason(cx, UncheckedUnwrap(&reason.toObject()));
    1029           0 :             RootedValue realReasonVal(cx, ObjectValue(*realReason));
    1030           0 :             RootedObject realGlobal(cx, &realReason->nonCCWGlobal());
    1031           0 :             ReportErrorToGlobal(cx, realGlobal, realReasonVal);
    1032             : 
    1033             :             // Async stacks are only properly adopted if there's at least one
    1034             :             // interpreter frame active right now. If a thenable job with a
    1035             :             // throwing `then` function got us here, that'll not be the case,
    1036             :             // so we add one by throwing the error from self-hosted code.
    1037           0 :             if (!GetInternalError(cx, JSMSG_PROMISE_ERROR_IN_WRAPPED_REJECTION_REASON, &reason))
    1038           0 :                 return false;
    1039             :         }
    1040             :     }
    1041             : 
    1042         112 :     MOZ_ASSERT(promise->state() == JS::PromiseState::Pending);
    1043             : 
    1044         224 :     return ResolvePromise(cx, promise, reason, JS::PromiseState::Rejected);
    1045             : }
    1046             : 
    1047             : // ES2016, 25.4.1.8.
    1048             : static MOZ_MUST_USE bool
    1049        2303 : TriggerPromiseReactions(JSContext* cx, HandleValue reactionsVal, JS::PromiseState state,
    1050             :                         HandleValue valueOrReason)
    1051             : {
    1052           0 :     RootedObject reactions(cx, &reactionsVal.toObject());
    1053        4606 :     RootedObject reaction(cx);
    1054             : 
    1055           0 :     if (reactions->is<PromiseReactionRecord>() ||
    1056           0 :         IsWrapper(reactions) ||
    1057         100 :         JS_IsDeadWrapper(reactions))
    1058             :     {
    1059        2203 :         return EnqueuePromiseReactionJob(cx, reactions, valueOrReason, state);
    1060             :     }
    1061             : 
    1062           0 :     RootedNativeObject reactionsList(cx, &reactions->as<NativeObject>());
    1063           0 :     size_t reactionsCount = reactionsList->getDenseInitializedLength();
    1064         100 :     MOZ_ASSERT(reactionsCount > 1, "Reactions list should be created lazily");
    1065             : 
    1066           0 :     RootedValue reactionVal(cx);
    1067           0 :     for (size_t i = 0; i < reactionsCount; i++) {
    1068           0 :         reactionVal = reactionsList->getDenseElement(i);
    1069           0 :         MOZ_RELEASE_ASSERT(reactionVal.isObject());
    1070           0 :         reaction = &reactionVal.toObject();
    1071         201 :         if (!EnqueuePromiseReactionJob(cx, reaction, valueOrReason, state))
    1072             :             return false;
    1073             :     }
    1074             : 
    1075             :     return true;
    1076             : }
    1077             : 
    1078             : static MOZ_MUST_USE bool
    1079        1034 : AsyncFunctionPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord*> reaction,
    1080             :                                 MutableHandleValue rval)
    1081             : {
    1082        1034 :     MOZ_ASSERT(reaction->isAsyncFunction());
    1083             : 
    1084           0 :     RootedValue handlerVal(cx, reaction->handler());
    1085           0 :     RootedValue argument(cx, reaction->handlerArg());
    1086           0 :     Rooted<PromiseObject*> resultPromise(cx, &reaction->promise()->as<PromiseObject>());
    1087        2068 :     RootedValue generatorVal(cx, resultPromise->getFixedSlot(PromiseSlot_AwaitGenerator));
    1088             : 
    1089        1034 :     int32_t handlerNum = int32_t(handlerVal.toNumber());
    1090             : 
    1091             :     // Await's handlers don't return a value, nor throw exception.
    1092             :     // They fail only on OOM.
    1093           0 :     if (handlerNum == PromiseHandlerAsyncFunctionAwaitedFulfilled) {
    1094        3006 :         if (!AsyncFunctionAwaitedFulfilled(cx, resultPromise, generatorVal, argument))
    1095             :             return false;
    1096             :     } else {
    1097           0 :         MOZ_ASSERT(handlerNum == PromiseHandlerAsyncFunctionAwaitedRejected);
    1098          96 :         if (!AsyncFunctionAwaitedRejected(cx, resultPromise, generatorVal, argument))
    1099             :             return false;
    1100             :     }
    1101             : 
    1102           0 :     rval.setUndefined();
    1103        1034 :     return true;
    1104             : }
    1105             : 
    1106             : static MOZ_MUST_USE bool
    1107           0 : AsyncGeneratorPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord*> reaction,
    1108             :                                  MutableHandleValue rval)
    1109             : {
    1110           0 :     MOZ_ASSERT(reaction->isAsyncGenerator());
    1111             : 
    1112           0 :     RootedValue handlerVal(cx, reaction->handler());
    1113           0 :     RootedValue argument(cx, reaction->handlerArg());
    1114           0 :     Rooted<AsyncGeneratorObject*> asyncGenObj(cx, reaction->asyncGenerator());
    1115             : 
    1116           0 :     int32_t handlerNum = int32_t(handlerVal.toNumber());
    1117             : 
    1118             :     // Await's handlers don't return a value, nor throw exception.
    1119             :     // They fail only on OOM.
    1120           0 :     if (handlerNum == PromiseHandlerAsyncGeneratorAwaitedFulfilled) {
    1121             :         // 4.1.1.
    1122           0 :         if (!AsyncGeneratorAwaitedFulfilled(cx, asyncGenObj, argument))
    1123             :             return false;
    1124           0 :     } else if (handlerNum == PromiseHandlerAsyncGeneratorAwaitedRejected) {
    1125             :         // 4.1.2.
    1126           0 :         if (!AsyncGeneratorAwaitedRejected(cx, asyncGenObj, argument))
    1127             :             return false;
    1128           0 :     } else if (handlerNum == PromiseHandlerAsyncGeneratorResumeNextReturnFulfilled) {
    1129           0 :         asyncGenObj->setCompleted();
    1130             :         // 11.4.3.5.1 step 1.
    1131           0 :         if (!AsyncGeneratorResolve(cx, asyncGenObj, argument, true))
    1132             :             return false;
    1133           0 :     } else if (handlerNum == PromiseHandlerAsyncGeneratorResumeNextReturnRejected) {
    1134           0 :         asyncGenObj->setCompleted();
    1135             :         // 11.4.3.5.2 step 1.
    1136           0 :         if (!AsyncGeneratorReject(cx, asyncGenObj, argument))
    1137             :             return false;
    1138           0 :     } else if (handlerNum == PromiseHandlerAsyncGeneratorYieldReturnAwaitedFulfilled) {
    1139           0 :         asyncGenObj->setExecuting();
    1140             :         // 11.4.3.7 steps 8.d-e.
    1141           0 :         if (!AsyncGeneratorYieldReturnAwaitedFulfilled(cx, asyncGenObj, argument))
    1142             :             return false;
    1143             :     } else {
    1144           0 :         MOZ_ASSERT(handlerNum == PromiseHandlerAsyncGeneratorYieldReturnAwaitedRejected);
    1145           0 :         asyncGenObj->setExecuting();
    1146             :         // 11.4.3.7 step 8.c.
    1147           0 :         if (!AsyncGeneratorYieldReturnAwaitedRejected(cx, asyncGenObj, argument))
    1148             :             return false;
    1149             :     }
    1150             : 
    1151           0 :     rval.setUndefined();
    1152           0 :     return true;
    1153             : }
    1154             : 
    1155             : // ES2016, 25.4.2.1.
    1156             : /**
    1157             :  * Callback triggering the fulfill/reject reaction for a resolved Promise,
    1158             :  * to be invoked by the embedding during its processing of the Promise job
    1159             :  * queue.
    1160             :  *
    1161             :  * See http://www.ecma-international.org/ecma-262/7.0/index.html#sec-jobs-and-job-queues
    1162             :  *
    1163             :  * A PromiseReactionJob is set as the native function of an extended
    1164             :  * JSFunction object, with all information required for the job's
    1165             :  * execution stored in in a reaction record in its first extended slot.
    1166             :  */
    1167             : static bool
    1168        2916 : PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp)
    1169             : {
    1170        2916 :     CallArgs args = CallArgsFromVp(argc, vp);
    1171             : 
    1172        5832 :     RootedFunction job(cx, &args.callee().as<JSFunction>());
    1173             : 
    1174        5832 :     RootedObject reactionObj(cx, &job->getExtendedSlot(ReactionJobSlot_ReactionRecord).toObject());
    1175             : 
    1176             :     // To ensure that the embedding ends up with the right entry global, we're
    1177             :     // guaranteeing that the reaction job function gets created in the same
    1178             :     // compartment as the handler function. That's not necessarily the global
    1179             :     // that the job was triggered from, though.
    1180             :     // We can find the triggering global via the job's reaction record. To go
    1181             :     // back, we check if the reaction is a wrapper and if so, unwrap it and
    1182             :     // enter its compartment.
    1183           0 :     mozilla::Maybe<AutoRealm> ar;
    1184           0 :     if (!IsProxy(reactionObj)) {
    1185        5824 :         MOZ_RELEASE_ASSERT(reactionObj->is<PromiseReactionRecord>());
    1186             :     } else {
    1187           0 :         reactionObj = UncheckedUnwrap(reactionObj);
    1188           1 :         if (JS_IsDeadWrapper(reactionObj)) {
    1189           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
    1190           0 :             return false;
    1191             :         }
    1192           0 :         MOZ_RELEASE_ASSERT(reactionObj->is<PromiseReactionRecord>());
    1193           4 :         ar.emplace(cx, reactionObj);
    1194             :     }
    1195             : 
    1196             :     // Steps 1-2.
    1197           0 :     Rooted<PromiseReactionRecord*> reaction(cx, &reactionObj->as<PromiseReactionRecord>());
    1198           0 :     if (reaction->isAsyncFunction())
    1199           0 :         return AsyncFunctionPromiseReactionJob(cx, reaction, args.rval());
    1200           0 :     if (reaction->isAsyncGenerator())
    1201           0 :         return AsyncGeneratorPromiseReactionJob(cx, reaction, args.rval());
    1202             : 
    1203             :     // Step 3.
    1204        3764 :     RootedValue handlerVal(cx, reaction->handler());
    1205             : 
    1206        3764 :     RootedValue argument(cx, reaction->handlerArg());
    1207             : 
    1208           0 :     RootedValue handlerResult(cx);
    1209        1882 :     ResolutionMode resolutionMode = ResolveMode;
    1210             : 
    1211             :     // Steps 4-6.
    1212           0 :     if (handlerVal.isNumber()) {
    1213         187 :         int32_t handlerNum = int32_t(handlerVal.toNumber());
    1214             : 
    1215             :         // Step 4.
    1216         187 :         if (handlerNum == PromiseHandlerIdentity) {
    1217             :             handlerResult = argument;
    1218          26 :         } else if (handlerNum == PromiseHandlerThrower) {
    1219             :             // Step 5.
    1220          26 :             resolutionMode = RejectMode;
    1221             :             handlerResult = argument;
    1222             :         } else {
    1223           0 :             MOZ_ASSERT(handlerNum == PromiseHandlerAsyncFromSyncIteratorValueUnwrapDone ||
    1224             :                        handlerNum == PromiseHandlerAsyncFromSyncIteratorValueUnwrapNotDone);
    1225             : 
    1226           0 :             bool done = handlerNum == PromiseHandlerAsyncFromSyncIteratorValueUnwrapDone;
    1227             :             // Async Iteration proposal 11.1.3.2.5 step 1.
    1228           0 :             RootedObject resultObj(cx, CreateIterResultObject(cx, argument, done));
    1229           0 :             if (!resultObj)
    1230           0 :                 return false;
    1231             : 
    1232           0 :             handlerResult = ObjectValue(*resultObj);
    1233             :         }
    1234             :     } else {
    1235             :         // Step 6.
    1236           0 :         FixedInvokeArgs<1> args2(cx);
    1237           0 :         args2[0].set(argument);
    1238           0 :         if (!Call(cx, handlerVal, UndefinedHandleValue, args2, &handlerResult)) {
    1239           0 :             resolutionMode = RejectMode;
    1240           0 :             if (!MaybeGetAndClearException(cx, &handlerResult))
    1241           0 :                 return false;
    1242             :         }
    1243             :     }
    1244             : 
    1245             :     // Steps 7-9.
    1246             :     size_t hookSlot = resolutionMode == RejectMode
    1247           0 :                       ? ReactionRecordSlot_Reject
    1248           0 :                       : ReactionRecordSlot_Resolve;
    1249           0 :     RootedObject callee(cx, reaction->getFixedSlot(hookSlot).toObjectOrNull());
    1250           0 :     RootedObject promiseObj(cx, reaction->promise());
    1251        5646 :     if (!RunResolutionFunction(cx, callee, handlerResult, resolutionMode, promiseObj))
    1252             :         return false;
    1253             : 
    1254           0 :     args.rval().setUndefined();
    1255        1882 :     return true;
    1256             : }
    1257             : 
    1258             : // ES2016, 25.4.2.2.
    1259             : /**
    1260             :  * Callback for resolving a thenable, to be invoked by the embedding during
    1261             :  * its processing of the Promise job queue.
    1262             :  *
    1263             :  * See http://www.ecma-international.org/ecma-262/7.0/index.html#sec-jobs-and-job-queues
    1264             :  *
    1265             :  * A PromiseResolveThenableJob is set as the native function of an extended
    1266             :  * JSFunction object, with all information required for the job's
    1267             :  * execution stored in the function's extended slots.
    1268             :  *
    1269             :  * Usage of the function's extended slots is as follows:
    1270             :  * ThenableJobSlot_Handler: The handler to use as the Promise reaction.
    1271             :  *                          This can be PromiseHandlerIdentity,
    1272             :  *                          PromiseHandlerThrower, or a callable. In the
    1273             :  *                          latter case, it's guaranteed to be an object
    1274             :  *                          from the same compartment as the
    1275             :  *                          PromiseReactionJob.
    1276             :  * ThenableJobSlot_JobData: JobData - a, potentially CCW-wrapped, dense list
    1277             :  *                          containing data required for proper execution of
    1278             :  *                          the reaction.
    1279             :  *
    1280             :  * The JobData list has the following entries:
    1281             :  * ThenableJobDataSlot_Promise: The Promise to resolve using the given
    1282             :  *                              thenable.
    1283             :  * ThenableJobDataSlot_Thenable: The thenable to use as the receiver when
    1284             :  *                               calling the `then` function.
    1285             :  */
    1286             : static bool
    1287        1232 : PromiseResolveThenableJob(JSContext* cx, unsigned argc, Value* vp)
    1288             : {
    1289        1232 :     CallArgs args = CallArgsFromVp(argc, vp);
    1290             : 
    1291           0 :     RootedFunction job(cx, &args.callee().as<JSFunction>());
    1292           0 :     RootedValue then(cx, job->getExtendedSlot(ThenableJobSlot_Handler));
    1293           0 :     MOZ_ASSERT(!IsWrapper(&then.toObject()));
    1294           0 :     RootedNativeObject jobArgs(cx, &job->getExtendedSlot(ThenableJobSlot_JobData)
    1295        3696 :                                     .toObject().as<NativeObject>());
    1296             : 
    1297           0 :     RootedObject promise(cx, &jobArgs->getDenseElement(ThenableJobDataIndex_Promise).toObject());
    1298        2464 :     RootedValue thenable(cx, jobArgs->getDenseElement(ThenableJobDataIndex_Thenable));
    1299             : 
    1300             :     // Step 1.
    1301           0 :     RootedObject resolveFn(cx);
    1302           0 :     RootedObject rejectFn(cx);
    1303        3696 :     if (!CreateResolvingFunctions(cx, promise, &resolveFn, &rejectFn))
    1304             :         return false;
    1305             : 
    1306             :     // Step 2.
    1307           0 :     FixedInvokeArgs<2> args2(cx);
    1308           0 :     args2[0].setObject(*resolveFn);
    1309        2464 :     args2[1].setObject(*rejectFn);
    1310             : 
    1311        2464 :     RootedValue rval(cx);
    1312             : 
    1313             :     // In difference to the usual pattern, we return immediately on success.
    1314        3696 :     if (Call(cx, then, thenable, args2, &rval))
    1315             :         return true;
    1316             : 
    1317           0 :     if (!MaybeGetAndClearException(cx, &rval))
    1318             :         return false;
    1319             : 
    1320           0 :     FixedInvokeArgs<1> rejectArgs(cx);
    1321           0 :     rejectArgs[0].set(rval);
    1322             : 
    1323           0 :     RootedValue rejectVal(cx, ObjectValue(*rejectFn));
    1324           0 :     return Call(cx, rejectVal, UndefinedHandleValue, rejectArgs, &rval);
    1325             : }
    1326             : 
    1327             : /**
    1328             :  * Tells the embedding to enqueue a Promise resolve thenable job, based on
    1329             :  * three parameters:
    1330             :  * promiseToResolve_ - The promise to resolve, obviously.
    1331             :  * thenable_ - The thenable to resolve the Promise with.
    1332             :  * thenVal - The `then` function to invoke with the `thenable` as the receiver.
    1333             :  */
    1334             : static MOZ_MUST_USE bool
    1335        1232 : EnqueuePromiseResolveThenableJob(JSContext* cx, HandleValue promiseToResolve_,
    1336             :                                  HandleValue thenable_, HandleValue thenVal)
    1337             : {
    1338             :     // Need to re-root these to enable wrapping them below.
    1339           0 :     RootedValue promiseToResolve(cx, promiseToResolve_);
    1340        2464 :     RootedValue thenable(cx, thenable_);
    1341             : 
    1342             :     // We enter the `then` callable's compartment so that the job function is
    1343             :     // created in that compartment.
    1344             :     // That guarantees that the embedding ends up with the right entry global.
    1345             :     // This is relevant for some html APIs like fetch that derive information
    1346             :     // from said global.
    1347           0 :     RootedObject then(cx, CheckedUnwrap(&thenVal.toObject()));
    1348        3696 :     AutoRealm ar(cx, then);
    1349             : 
    1350           0 :     RootedAtom funName(cx, cx->names().empty);
    1351           0 :     RootedFunction job(cx, NewNativeFunction(cx, PromiseResolveThenableJob, 0, funName,
    1352           0 :                                              gc::AllocKind::FUNCTION_EXTENDED, GenericObject));
    1353        1232 :     if (!job)
    1354             :         return false;
    1355             : 
    1356             :     // Store the `then` function on the callback.
    1357        3696 :     job->setExtendedSlot(ThenableJobSlot_Handler, ObjectValue(*then));
    1358             : 
    1359             :     // Create a dense array to hold the data needed for the reaction job to
    1360             :     // work.
    1361             :     // See the doc comment for PromiseResolveThenableJob for the layout.
    1362           0 :     RootedArrayObject data(cx, NewDenseFullyAllocatedArray(cx, ThenableJobDataLength));
    1363           0 :     if (!data ||
    1364        2464 :         data->ensureDenseElements(cx, 0, ThenableJobDataLength) != DenseElementResult::Success)
    1365             :     {
    1366             :         return false;
    1367             :     }
    1368             : 
    1369             :     // Wrap and set the `promiseToResolve` argument.
    1370        2464 :     if (!cx->compartment()->wrap(cx, &promiseToResolve))
    1371             :         return false;
    1372        2464 :     data->setDenseElement(ThenableJobDataIndex_Promise, promiseToResolve);
    1373             :     // At this point the promise is guaranteed to be wrapped into the job's
    1374             :     // compartment.
    1375        2464 :     RootedObject promise(cx, &promiseToResolve.toObject());
    1376             : 
    1377             :     // Wrap and set the `thenable` argument.
    1378           0 :     MOZ_ASSERT(thenable.isObject());
    1379        2464 :     if (!cx->compartment()->wrap(cx, &thenable))
    1380             :         return false;
    1381        2464 :     data->setDenseElement(ThenableJobDataIndex_Thenable, thenable);
    1382             : 
    1383             :     // Store the data array on the reaction job.
    1384        3696 :     job->setExtendedSlot(ThenableJobSlot_JobData, ObjectValue(*data));
    1385             : 
    1386           0 :     RootedObject incumbentGlobal(cx, cx->runtime()->getIncumbentGlobal(cx));
    1387        4928 :     return cx->runtime()->enqueuePromiseJob(cx, job, promise, incumbentGlobal);
    1388             : }
    1389             : 
    1390             : static MOZ_MUST_USE bool
    1391             : AddPromiseReaction(JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled,
    1392             :                    HandleValue onRejected, HandleObject dependentPromise,
    1393             :                    HandleObject resolve, HandleObject reject, HandleObject incumbentGlobal);
    1394             : 
    1395             : static MOZ_MUST_USE bool
    1396             : AddPromiseReaction(JSContext* cx, Handle<PromiseObject*> promise,
    1397             :                    Handle<PromiseReactionRecord*> reaction);
    1398             : 
    1399             : static MOZ_MUST_USE bool BlockOnPromise(JSContext* cx, HandleValue promise,
    1400             :                                         HandleObject blockedPromise,
    1401             :                                         HandleValue onFulfilled, HandleValue onRejected);
    1402             : 
    1403             : static JSFunction*
    1404          66 : GetResolveFunctionFromReject(JSFunction* reject)
    1405             : {
    1406           0 :     MOZ_ASSERT(reject->maybeNative() == RejectPromiseFunction);
    1407           0 :     Value resolveFunVal = reject->getExtendedSlot(RejectFunctionSlot_ResolveFunction);
    1408           0 :     MOZ_ASSERT(IsNativeFunction(resolveFunVal, ResolvePromiseFunction));
    1409          66 :     return &resolveFunVal.toObject().as<JSFunction>();
    1410             : }
    1411             : 
    1412             : static JSFunction*
    1413        1503 : GetRejectFunctionFromResolve(JSFunction* resolve)
    1414             : {
    1415           0 :     MOZ_ASSERT(resolve->maybeNative() == ResolvePromiseFunction);
    1416           0 :     Value rejectFunVal = resolve->getExtendedSlot(ResolveFunctionSlot_RejectFunction);
    1417           0 :     MOZ_ASSERT(IsNativeFunction(rejectFunVal, RejectPromiseFunction));
    1418        1503 :     return &rejectFunVal.toObject().as<JSFunction>();
    1419             : }
    1420             : 
    1421             : static JSFunction*
    1422           0 : GetResolveFunctionFromPromise(PromiseObject* promise)
    1423             : {
    1424           0 :     Value rejectFunVal = promise->getFixedSlot(PromiseSlot_RejectFunction);
    1425           0 :     if (rejectFunVal.isUndefined())
    1426             :         return nullptr;
    1427           0 :     JSObject* rejectFunObj = &rejectFunVal.toObject();
    1428             : 
    1429             :     // We can safely unwrap it because all we want is to get the resolve
    1430             :     // function.
    1431           0 :     if (IsWrapper(rejectFunObj))
    1432           0 :         rejectFunObj = UncheckedUnwrap(rejectFunObj);
    1433             : 
    1434           0 :     if (!rejectFunObj->is<JSFunction>())
    1435             :         return nullptr;
    1436             : 
    1437           0 :     JSFunction* rejectFun = &rejectFunObj->as<JSFunction>();
    1438             : 
    1439             :     // Only the original RejectPromiseFunction has a reference to the resolve
    1440             :     // function.
    1441           0 :     if (rejectFun->maybeNative() != &RejectPromiseFunction)
    1442             :         return nullptr;
    1443             : 
    1444           0 :     return GetResolveFunctionFromReject(rejectFun);
    1445             : }
    1446             : 
    1447             : static void
    1448        1569 : ClearResolutionFunctionSlots(JSFunction* resolutionFun)
    1449             : {
    1450             :     JSFunction* resolve;
    1451             :     JSFunction* reject;
    1452           0 :     if (resolutionFun->maybeNative() == ResolvePromiseFunction) {
    1453           0 :         resolve = resolutionFun;
    1454        1503 :         reject = GetRejectFunctionFromResolve(resolutionFun);
    1455             :     } else {
    1456           0 :         resolve = GetResolveFunctionFromReject(resolutionFun);
    1457          66 :         reject = resolutionFun;
    1458             :     }
    1459             : 
    1460           0 :     resolve->setExtendedSlot(ResolveFunctionSlot_Promise, UndefinedValue());
    1461        1569 :     resolve->setExtendedSlot(ResolveFunctionSlot_RejectFunction, UndefinedValue());
    1462             : 
    1463           0 :     reject->setExtendedSlot(RejectFunctionSlot_Promise, UndefinedValue());
    1464           0 :     reject->setExtendedSlot(RejectFunctionSlot_ResolveFunction, UndefinedValue());
    1465        1569 : }
    1466             : 
    1467             : // ES2016, 25.4.3.1. steps 3-7.
    1468             : static MOZ_MUST_USE MOZ_ALWAYS_INLINE PromiseObject*
    1469        4410 : CreatePromiseObjectInternal(JSContext* cx, HandleObject proto /* = nullptr */,
    1470             :                             bool protoIsWrapped /* = false */, bool informDebugger /* = true */)
    1471             : {
    1472             :     // Step 3.
    1473             :     // Enter the unwrapped proto's compartment, if that's different from
    1474             :     // the current one.
    1475             :     // All state stored in a Promise's fixed slots must be created in the
    1476             :     // same compartment, so we get all of that out of the way here.
    1477             :     // (Except for the resolution functions, which are created below.)
    1478           0 :     mozilla::Maybe<AutoRealm> ar;
    1479           0 :     if (protoIsWrapped)
    1480           8 :         ar.emplace(cx, proto);
    1481             : 
    1482           0 :     PromiseObject* promise = NewObjectWithClassProto<PromiseObject>(cx, proto);
    1483        4410 :     if (!promise)
    1484             :         return nullptr;
    1485             : 
    1486             :     // Step 4.
    1487        4410 :     promise->initFixedSlot(PromiseSlot_Flags, Int32Value(0));
    1488             : 
    1489             :     // Steps 5-6.
    1490             :     // Omitted, we allocate our single list of reaction records lazily.
    1491             : 
    1492             :     // Step 7.
    1493             :     // Implicit, the handled flag is unset by default.
    1494             : 
    1495           0 :     if (MOZ_LIKELY(!ShouldCaptureDebugInfo(cx)))
    1496           0 :         return promise;
    1497             : 
    1498             :     // Store an allocation stack so we can later figure out what the
    1499             :     // control flow was for some unexpected results. Frightfully expensive,
    1500             :     // but oh well.
    1501             : 
    1502        8820 :     Rooted<PromiseObject*> promiseRoot(cx, promise);
    1503             : 
    1504           0 :     PromiseDebugInfo* debugInfo = PromiseDebugInfo::create(cx, promiseRoot);
    1505        4410 :     if (!debugInfo)
    1506             :         return nullptr;
    1507             : 
    1508             :     // Let the Debugger know about this Promise.
    1509           0 :     if (informDebugger)
    1510        4045 :         Debugger::onNewPromise(cx, promiseRoot);
    1511             : 
    1512        4410 :     return promiseRoot;
    1513             : }
    1514             : 
    1515             : // ES2016, 25.4.3.1.
    1516             : static bool
    1517         365 : PromiseConstructor(JSContext* cx, unsigned argc, Value* vp)
    1518             : {
    1519         365 :     CallArgs args = CallArgsFromVp(argc, vp);
    1520             : 
    1521             :     // Step 1.
    1522         365 :     if (!ThrowIfNotConstructing(cx, args, "Promise"))
    1523             :         return false;
    1524             : 
    1525             :     // Step 2.
    1526           0 :     RootedValue executorVal(cx, args.get(0));
    1527           0 :     if (!IsCallable(executorVal))
    1528           0 :         return ReportIsNotFunction(cx, executorVal);
    1529         730 :     RootedObject executor(cx, &executorVal.toObject());
    1530             : 
    1531             :     // Steps 3-10.
    1532        1095 :     RootedObject newTarget(cx, &args.newTarget().toObject());
    1533             : 
    1534             :     // If the constructor is called via an Xray wrapper, then the newTarget
    1535             :     // hasn't been unwrapped. We want that because, while the actual instance
    1536             :     // should be created in the target compartment, the constructor's code
    1537             :     // should run in the wrapper's compartment.
    1538             :     //
    1539             :     // This is so that the resolve and reject callbacks get created in the
    1540             :     // wrapper's compartment, which is required for code in that compartment
    1541             :     // to freely interact with it, and, e.g., pass objects as arguments, which
    1542             :     // it wouldn't be able to if the callbacks were themselves wrapped in Xray
    1543             :     // wrappers.
    1544             :     //
    1545             :     // At the same time, just creating the Promise itself in the wrapper's
    1546             :     // compartment wouldn't be helpful: if the wrapper forbids interactions
    1547             :     // with objects except for specific actions, such as calling them, then
    1548             :     // the code we want to expose it to can't actually treat it as a Promise:
    1549             :     // calling .then on it would throw, for example.
    1550             :     //
    1551             :     // Another scenario where it's important to create the Promise in a
    1552             :     // different compartment from the resolution functions is when we want to
    1553             :     // give non-privileged code a Promise resolved with the result of a
    1554             :     // Promise from privileged code; as a return value of a JS-implemented
    1555             :     // API, say. If the resolution functions were unprivileged, then resolving
    1556             :     // with a privileged Promise would cause `resolve` to attempt accessing
    1557             :     // .then on the passed Promise, which would throw an exception, so we'd
    1558             :     // just end up with a rejected Promise. Really, we want to chain the two
    1559             :     // Promises, with the unprivileged one resolved with the resolution of the
    1560             :     // privileged one.
    1561             : 
    1562           0 :     bool needsWrapping = false;
    1563           0 :     RootedObject proto(cx);
    1564           0 :     if (IsWrapper(newTarget)) {
    1565           0 :         JSObject* unwrappedNewTarget = CheckedUnwrap(newTarget);
    1566           0 :         MOZ_ASSERT(unwrappedNewTarget);
    1567          16 :         MOZ_ASSERT(unwrappedNewTarget != newTarget);
    1568             : 
    1569          16 :         newTarget = unwrappedNewTarget;
    1570             :         {
    1571           0 :             AutoRealm ar(cx, newTarget);
    1572           0 :             Handle<GlobalObject*> global = cx->global();
    1573           0 :             RootedObject promiseCtor(cx, GlobalObject::getOrCreatePromiseConstructor(cx, global));
    1574           1 :             if (!promiseCtor)
    1575           0 :                 return false;
    1576             : 
    1577             :             // Promise subclasses don't get the special Xray treatment, so
    1578             :             // we only need to do the complex wrapping and unwrapping scheme
    1579             :             // described above for instances of Promise itself.
    1580           0 :             if (newTarget == promiseCtor) {
    1581           0 :                 needsWrapping = true;
    1582           0 :                 proto = GlobalObject::getOrCreatePromisePrototype(cx, cx->global());
    1583           8 :                 if (!proto)
    1584             :                     return false;
    1585             :             }
    1586             :         }
    1587             :     }
    1588             : 
    1589           0 :     if (needsWrapping) {
    1590          16 :         if (!cx->compartment()->wrap(cx, &proto))
    1591             :             return false;
    1592             :     } else {
    1593         357 :         if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto))
    1594             :             return false;
    1595             :     }
    1596           0 :     PromiseObject* promise = PromiseObject::create(cx, executor, proto, needsWrapping);
    1597         365 :     if (!promise)
    1598             :         return false;
    1599             : 
    1600             :     // Step 11.
    1601           0 :     args.rval().setObject(*promise);
    1602           0 :     if (needsWrapping)
    1603          16 :         return cx->compartment()->wrap(cx, args.rval());
    1604             :     return true;
    1605             : }
    1606             : 
    1607             : // ES2016, 25.4.3.1. steps 3-11.
    1608             : /* static */ PromiseObject*
    1609         365 : PromiseObject::create(JSContext* cx, HandleObject executor, HandleObject proto /* = nullptr */,
    1610             :                       bool needsWrapping /* = false */)
    1611             : {
    1612         730 :     MOZ_ASSERT(executor->isCallable());
    1613             : 
    1614         730 :     RootedObject usedProto(cx, proto);
    1615             :     // If the proto is wrapped, that means the current function is running
    1616             :     // with a different compartment active from the one the Promise instance
    1617             :     // is to be created in.
    1618             :     // See the comment in PromiseConstructor for details.
    1619           0 :     if (needsWrapping) {
    1620           0 :         MOZ_ASSERT(proto);
    1621           0 :         usedProto = CheckedUnwrap(proto);
    1622           8 :         if (!usedProto)
    1623             :             return nullptr;
    1624             :     }
    1625             : 
    1626             : 
    1627             :     // Steps 3-7.
    1628           0 :     Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx, usedProto, needsWrapping,
    1629           0 :                                                                    false));
    1630         365 :     if (!promise)
    1631             :         return nullptr;
    1632             : 
    1633           0 :     RootedObject promiseObj(cx, promise);
    1634         381 :     if (needsWrapping && !cx->compartment()->wrap(cx, &promiseObj))
    1635             :         return nullptr;
    1636             : 
    1637             :     // Step 8.
    1638             :     // The resolving functions are created in the compartment active when the
    1639             :     // (maybe wrapped) Promise constructor was called. They contain checks and
    1640             :     // can unwrap the Promise if required.
    1641           0 :     RootedObject resolveFn(cx);
    1642           0 :     RootedObject rejectFn(cx);
    1643        1095 :     if (!CreateResolvingFunctions(cx, promiseObj, &resolveFn, &rejectFn))
    1644             :         return nullptr;
    1645             : 
    1646             :     // Need to wrap the resolution functions before storing them on the Promise.
    1647         730 :     MOZ_ASSERT(promise->getFixedSlot(PromiseSlot_RejectFunction).isUndefined(),
    1648             :                "Slot must be undefined so initFixedSlot can be used");
    1649           0 :     if (needsWrapping) {
    1650           0 :         AutoRealm ar(cx, promise);
    1651           0 :         RootedObject wrappedRejectFn(cx, rejectFn);
    1652           1 :         if (!cx->compartment()->wrap(cx, &wrappedRejectFn))
    1653           0 :             return nullptr;
    1654          24 :         promise->initFixedSlot(PromiseSlot_RejectFunction, ObjectValue(*wrappedRejectFn));
    1655             :     } else {
    1656        1071 :         promise->initFixedSlot(PromiseSlot_RejectFunction, ObjectValue(*rejectFn));
    1657             :     }
    1658             : 
    1659             :     // Step 9.
    1660             :     bool success;
    1661             :     {
    1662        1095 :         FixedInvokeArgs<2> args(cx);
    1663             : 
    1664           0 :         args[0].setObject(*resolveFn);
    1665         730 :         args[1].setObject(*rejectFn);
    1666             : 
    1667           0 :         RootedValue calleeOrRval(cx, ObjectValue(*executor));
    1668         730 :         success = Call(cx, calleeOrRval, UndefinedHandleValue, args, &calleeOrRval);
    1669             :     }
    1670             : 
    1671             :     // Step 10.
    1672           0 :     if (!success) {
    1673           0 :         RootedValue exceptionVal(cx);
    1674           0 :         if (!MaybeGetAndClearException(cx, &exceptionVal))
    1675           0 :             return nullptr;
    1676             : 
    1677           0 :         FixedInvokeArgs<1> args(cx);
    1678             : 
    1679           0 :         args[0].set(exceptionVal);
    1680             : 
    1681           0 :         RootedValue calleeOrRval(cx, ObjectValue(*rejectFn));
    1682           0 :         if (!Call(cx, calleeOrRval, UndefinedHandleValue, args, &calleeOrRval))
    1683           0 :             return nullptr;
    1684             :     }
    1685             : 
    1686             :     // Let the Debugger know about this Promise.
    1687         730 :     Debugger::onNewPromise(cx, promise);
    1688             : 
    1689             :     // Step 11.
    1690         365 :     return promise;
    1691             : }
    1692             : 
    1693             : // ES2016, 25.4.3.1. skipping creation of resolution functions and executor
    1694             : // function invocation.
    1695             : /* static */ PromiseObject*
    1696          97 : PromiseObject::createSkippingExecutor(JSContext* cx)
    1697             : {
    1698          97 :     return CreatePromiseObjectWithoutResolutionFunctions(cx);
    1699             : }
    1700             : 
    1701             : static MOZ_MUST_USE bool PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator,
    1702             :                                            HandleObject C, HandleObject promiseObj,
    1703             :                                            HandleObject resolve, HandleObject reject,
    1704             :                                            bool* done);
    1705             : 
    1706             : // ES2016, 25.4.4.1.
    1707             : static bool
    1708          85 : Promise_static_all(JSContext* cx, unsigned argc, Value* vp)
    1709             : {
    1710           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1711         170 :     RootedValue iterable(cx, args.get(0));
    1712             : 
    1713             :     // Step 2 (reordered).
    1714           0 :     RootedValue CVal(cx, args.thisv());
    1715          85 :     if (!CVal.isObject()) {
    1716             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
    1717           0 :                                   "Receiver of Promise.all call");
    1718           0 :         return false;
    1719             :     }
    1720             : 
    1721             :     // Step 1.
    1722         170 :     RootedObject C(cx, &CVal.toObject());
    1723             : 
    1724             :     // Step 3.
    1725           0 :     RootedObject resultPromise(cx);
    1726           0 :     RootedObject resolve(cx);
    1727           0 :     RootedObject reject(cx);
    1728         340 :     if (!NewPromiseCapability(cx, C, &resultPromise, &resolve, &reject, false))
    1729             :         return false;
    1730             : 
    1731             :     // Steps 4-5.
    1732           0 :     JS::ForOfIterator iter(cx);
    1733           0 :     if (!iter.init(iterable, JS::ForOfIterator::AllowNonIterable))
    1734           0 :         return AbruptRejectPromise(cx, args, resultPromise, reject);
    1735             : 
    1736          85 :     if (!iter.valueIsIterable()) {
    1737             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE,
    1738           0 :                                   "Argument of Promise.all");
    1739           0 :         return AbruptRejectPromise(cx, args, resultPromise, reject);
    1740             :     }
    1741             : 
    1742             :     // Step 6 (implicit).
    1743             : 
    1744             :     // Step 7.
    1745             :     bool done;
    1746         340 :     bool result = PerformPromiseAll(cx, iter, C, resultPromise, resolve, reject, &done);
    1747             : 
    1748             :     // Step 8.
    1749          85 :     if (!result) {
    1750             :         // Step 8.a.
    1751           0 :         if (!done)
    1752           0 :             iter.closeThrow();
    1753             : 
    1754             :         // Step 8.b.
    1755           0 :         return AbruptRejectPromise(cx, args, resultPromise, reject);
    1756             :     }
    1757             : 
    1758             :     // Step 9.
    1759           0 :     args.rval().setObject(*resultPromise);
    1760          85 :     return true;
    1761             : }
    1762             : 
    1763             : static MOZ_MUST_USE bool PerformPromiseThen(JSContext* cx, Handle<PromiseObject*> promise,
    1764             :                                             HandleValue onFulfilled_, HandleValue onRejected_,
    1765             :                                             HandleObject resultPromise,
    1766             :                                             HandleObject resolve, HandleObject reject);
    1767             : 
    1768             : static bool PromiseAllResolveElementFunction(JSContext* cx, unsigned argc, Value* vp);
    1769             : 
    1770             : // Unforgeable version of ES2016, 25.4.4.1.
    1771             : MOZ_MUST_USE JSObject*
    1772           0 : js::GetWaitForAllPromise(JSContext* cx, const JS::AutoObjectVector& promises)
    1773             : {
    1774             : #ifdef DEBUG
    1775           0 :     for (size_t i = 0, len = promises.length(); i < len; i++) {
    1776           0 :         JSObject* obj = promises[i];
    1777           0 :         assertSameCompartment(cx, obj);
    1778           0 :         MOZ_ASSERT(UncheckedUnwrap(obj)->is<PromiseObject>());
    1779             :     }
    1780             : #endif
    1781             : 
    1782             :     // Step 1.
    1783           0 :     RootedObject C(cx, GlobalObject::getOrCreatePromiseConstructor(cx, cx->global()));
    1784           0 :     if (!C)
    1785             :         return nullptr;
    1786             : 
    1787             :     // Step 2 (omitted).
    1788             : 
    1789             :     // Step 3.
    1790           0 :     RootedObject resultPromise(cx);
    1791           0 :     RootedObject resolve(cx);
    1792           0 :     RootedObject reject(cx);
    1793           0 :     if (!NewPromiseCapability(cx, C, &resultPromise, &resolve, &reject, false))
    1794             :         return nullptr;
    1795             : 
    1796             :     // Steps 4-6 (omitted).
    1797             : 
    1798             :     // Step 7.
    1799             :     // Implemented as an inlined, simplied version of ES2016 25.4.4.1.1, PerformPromiseAll.
    1800             :     {
    1801           0 :         uint32_t promiseCount = promises.length();
    1802             :         // Sub-steps 1-2 (omitted).
    1803             : 
    1804             :         // Sub-step 3.
    1805           0 :         RootedNativeObject valuesArray(cx, NewDenseFullyAllocatedArray(cx, promiseCount));
    1806           0 :         if (!valuesArray)
    1807           0 :             return nullptr;
    1808           0 :         if (valuesArray->ensureDenseElements(cx, 0, promiseCount) != DenseElementResult::Success)
    1809             :             return nullptr;
    1810             : 
    1811             :         // Sub-step 4.
    1812             :         // Create our data holder that holds all the things shared across
    1813             :         // every step of the iterator.  In particular, this holds the
    1814             :         // remainingElementsCount (as an integer reserved slot), the array of
    1815             :         // values, and the resolve function from our PromiseCapability.
    1816           0 :         RootedValue valuesArrayVal(cx, ObjectValue(*valuesArray));
    1817           0 :         Rooted<PromiseAllDataHolder*> dataHolder(cx, NewPromiseAllDataHolder(cx, resultPromise,
    1818             :                                                                              valuesArrayVal,
    1819           0 :                                                                              resolve));
    1820           0 :         if (!dataHolder)
    1821           0 :             return nullptr;
    1822           0 :         RootedValue dataHolderVal(cx, ObjectValue(*dataHolder));
    1823             : 
    1824             :         // Sub-step 5 (inline in loop-header below).
    1825             : 
    1826             :         // Sub-step 6.
    1827           0 :         for (uint32_t index = 0; index < promiseCount; index++) {
    1828             :             // Steps a-c (omitted).
    1829             :             // Step d (implemented after the loop).
    1830             :             // Steps e-g (omitted).
    1831             : 
    1832             :             // Step h.
    1833           0 :             valuesArray->setDenseElement(index, UndefinedHandleValue);
    1834             : 
    1835             :             // Step i, vastly simplified.
    1836           0 :             RootedObject nextPromiseObj(cx, promises[index]);
    1837             : 
    1838             :             // Step j.
    1839           0 :             RootedFunction resolveFunc(cx, NewNativeFunction(cx, PromiseAllResolveElementFunction,
    1840             :                                                              1, nullptr,
    1841             :                                                              gc::AllocKind::FUNCTION_EXTENDED,
    1842           0 :                                                              GenericObject));
    1843           0 :             if (!resolveFunc)
    1844           0 :                 return nullptr;
    1845             : 
    1846             :             // Steps k-o.
    1847           0 :             resolveFunc->setExtendedSlot(PromiseAllResolveElementFunctionSlot_Data, dataHolderVal);
    1848           0 :             resolveFunc->setExtendedSlot(PromiseAllResolveElementFunctionSlot_ElementIndex,
    1849           0 :                                          Int32Value(index));
    1850             : 
    1851             :             // Step p.
    1852           0 :             dataHolder->increaseRemainingCount();
    1853             : 
    1854             :             // Step q, very roughly.
    1855           0 :             RootedValue resolveFunVal(cx, ObjectValue(*resolveFunc));
    1856           0 :             RootedValue rejectFunVal(cx, ObjectValue(*reject));
    1857           0 :             Rooted<PromiseObject*> nextPromise(cx);
    1858             : 
    1859             :             // GetWaitForAllPromise is used internally only and must not
    1860             :             // trigger content-observable effects when registering a reaction.
    1861             :             // It's also meant to work on wrapped Promises, potentially from
    1862             :             // compartments with principals inaccessible from the current
    1863             :             // compartment. To make that work, it unwraps promises with
    1864             :             // UncheckedUnwrap,
    1865           0 :             nextPromise = &UncheckedUnwrap(nextPromiseObj)->as<PromiseObject>();
    1866             : 
    1867           0 :             if (!PerformPromiseThen(cx, nextPromise, resolveFunVal, rejectFunVal,
    1868             :                                     resultPromise, nullptr, nullptr))
    1869             :             {
    1870           0 :                 return nullptr;
    1871             :             }
    1872             : 
    1873             :             // Step r (inline in loop-header).
    1874             :         }
    1875             : 
    1876             :         // Sub-step d.i (implicit).
    1877             :         // Sub-step d.ii.
    1878           0 :         int32_t remainingCount = dataHolder->decreaseRemainingCount();
    1879             : 
    1880             :         // Sub-step d.iii-iv.
    1881           0 :         if (remainingCount == 0) {
    1882           0 :             RootedValue valuesArrayVal(cx, ObjectValue(*valuesArray));
    1883           0 :             if (!ResolvePromiseInternal(cx, resultPromise, valuesArrayVal))
    1884           0 :                 return nullptr;
    1885             :         }
    1886             :     }
    1887             : 
    1888             :     // Step 8 (omitted).
    1889             : 
    1890             :     // Step 9.
    1891           0 :     return resultPromise;
    1892             : }
    1893             : 
    1894             : static MOZ_MUST_USE bool
    1895        2103 : RunResolutionFunction(JSContext *cx, HandleObject resolutionFun, HandleValue result,
    1896             :                       ResolutionMode mode, HandleObject promiseObj)
    1897             : {
    1898             :     // The absence of a resolve/reject function can mean that, as an
    1899             :     // optimization, those weren't created. In that case, a flag is set on
    1900             :     // the Promise object. (It's also possible to not have a resolution
    1901             :     // function without that flag being set. This can occur if a Promise
    1902             :     // subclass constructor passes null/undefined to `super()`.)
    1903             :     // There are also reactions where the Promise itself is missing. For
    1904             :     // those, there's nothing left to do here.
    1905           0 :     assertSameCompartment(cx, resolutionFun);
    1906           0 :     assertSameCompartment(cx, result);
    1907           0 :     assertSameCompartment(cx, promiseObj);
    1908           0 :     if (resolutionFun) {
    1909           0 :         RootedValue calleeOrRval(cx, ObjectValue(*resolutionFun));
    1910           0 :         FixedInvokeArgs<1> resolveArgs(cx);
    1911           0 :         resolveArgs[0].set(result);
    1912         178 :         return Call(cx, calleeOrRval, UndefinedHandleValue, resolveArgs, &calleeOrRval);
    1913             :     }
    1914             : 
    1915        2014 :     if (!promiseObj)
    1916             :         return true;
    1917             : 
    1918           0 :     Rooted<PromiseObject*> promise(cx, &promiseObj->as<PromiseObject>());
    1919        1919 :     if (promise->state() != JS::PromiseState::Pending)
    1920             :         return true;
    1921             : 
    1922           0 :     if (mode == ResolveMode) {
    1923        1811 :         if (!PromiseHasAnyFlag(*promise, PROMISE_FLAG_DEFAULT_RESOLVE_FUNCTION))
    1924             :             return true;
    1925        1656 :         return ResolvePromiseInternal(cx, promise, result);
    1926             :     }
    1927             : 
    1928          26 :     if (!PromiseHasAnyFlag(*promise, PROMISE_FLAG_DEFAULT_REJECT_FUNCTION))
    1929             :         return true;
    1930          26 :     return RejectMaybeWrappedPromise(cx, promiseObj, result);
    1931             : }
    1932             : 
    1933             : // ES2016, 25.4.4.1.1.
    1934             : static MOZ_MUST_USE bool
    1935          85 : PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
    1936             :                   HandleObject promiseObj, HandleObject resolve, HandleObject reject,
    1937             :                   bool* done)
    1938             : {
    1939          85 :     *done = false;
    1940             : 
    1941           0 :     RootedObject unwrappedPromiseObj(cx);
    1942           0 :     if (IsWrapper(promiseObj)) {
    1943           0 :         unwrappedPromiseObj = CheckedUnwrap(promiseObj);
    1944           0 :         MOZ_ASSERT(unwrappedPromiseObj);
    1945             :     }
    1946             : 
    1947             :     // Step 1.
    1948           0 :     MOZ_ASSERT(C->isConstructor());
    1949         255 :     RootedValue CVal(cx, ObjectValue(*C));
    1950             : 
    1951             :     // Step 2 (omitted).
    1952             : 
    1953             :     // Step 3.
    1954             :     // We have to be very careful about which compartments we create things in
    1955             :     // here.  In particular, we have to maintain the invariant that anything
    1956             :     // stored in a reserved slot is same-compartment with the object whose
    1957             :     // reserved slot it's in.  But we want to create the values array in the
    1958             :     // Promise's compartment, because that array can get exposed to
    1959             :     // code that has access to the Promise (in particular code from
    1960             :     // that compartment), and that should work, even if the Promise
    1961             :     // compartment is less-privileged than our caller compartment.
    1962             :     //
    1963             :     // So the plan is as follows: Create the values array in the promise
    1964             :     // compartment.  Create the PromiseAllResolveElement function
    1965             :     // and the data holder in our current compartment.  Store a
    1966             :     // cross-compartment wrapper to the values array in the holder.  This
    1967             :     // should be OK because the only things we hand the
    1968             :     // PromiseAllResolveElement function to are the "then" calls we do and in
    1969             :     // the case when the Promise's compartment is not the current compartment
    1970             :     // those are happening over Xrays anyway, which means they get the
    1971             :     // canonical "then" function and content can't see our
    1972             :     // PromiseAllResolveElement.
    1973           0 :     RootedObject valuesArray(cx);
    1974           0 :     if (unwrappedPromiseObj) {
    1975           0 :         JSAutoRealm ar(cx, unwrappedPromiseObj);
    1976           0 :         valuesArray = NewDenseFullyAllocatedArray(cx, 0);
    1977             :     } else {
    1978         170 :         valuesArray = NewDenseFullyAllocatedArray(cx, 0);
    1979             :     }
    1980          85 :     if (!valuesArray)
    1981             :         return false;
    1982             : 
    1983           0 :     RootedValue valuesArrayVal(cx, ObjectValue(*valuesArray));
    1984         170 :     if (!cx->compartment()->wrap(cx, &valuesArrayVal))
    1985             :         return false;
    1986             : 
    1987             :     // Step 4.
    1988             :     // Create our data holder that holds all the things shared across
    1989             :     // every step of the iterator.  In particular, this holds the
    1990             :     // remainingElementsCount (as an integer reserved slot), the array of
    1991             :     // values, and the resolve function from our PromiseCapability.
    1992           0 :     Rooted<PromiseAllDataHolder*> dataHolder(cx, NewPromiseAllDataHolder(cx, promiseObj,
    1993           0 :                                                                          valuesArrayVal, resolve));
    1994          85 :     if (!dataHolder)
    1995             :         return false;
    1996         255 :     RootedValue dataHolderVal(cx, ObjectValue(*dataHolder));
    1997             : 
    1998             :     // Step 5.
    1999          85 :     uint32_t index = 0;
    2000             : 
    2001             :     // Step 6.
    2002           0 :     RootedValue nextValue(cx);
    2003           0 :     RootedId indexId(cx);
    2004         255 :     RootedValue rejectFunVal(cx, ObjectValue(*reject));
    2005             : 
    2006             :     while (true) {
    2007             :         // Steps a-c, e-g.
    2008         315 :         if (!iterator.next(&nextValue, done)) {
    2009             :             // Steps b, f.
    2010           0 :             *done = true;
    2011             : 
    2012             :             // Steps c, g.
    2013          85 :             return false;
    2014             :         }
    2015             : 
    2016             :         // Step d.
    2017         315 :         if (*done) {
    2018             :             // Step d.i (implicit).
    2019             : 
    2020             :             // Step d.ii.
    2021          85 :             int32_t remainingCount = dataHolder->decreaseRemainingCount();
    2022             : 
    2023             :             // Steps d.iii-iv.
    2024           0 :             if (remainingCount == 0) {
    2025           0 :                 return RunResolutionFunction(cx, resolve, valuesArrayVal, ResolveMode,
    2026          10 :                                              promiseObj);
    2027             :             }
    2028             : 
    2029             :             // We're all set for now!
    2030             :             return true;
    2031             :         }
    2032             : 
    2033             :         // Step h.
    2034             :         { // Scope for the JSAutoRealm we need to work with valuesArray.  We
    2035             :             // mostly do this for performance; we could go ahead and do the define via
    2036             :             // a cross-compartment proxy instead...
    2037           0 :             JSAutoRealm ar(cx, valuesArray);
    2038           0 :             indexId = INT_TO_JSID(index);
    2039           1 :             if (!DefineDataProperty(cx, valuesArray, indexId, UndefinedHandleValue))
    2040           0 :                 return false;
    2041             :         }
    2042             : 
    2043             :         // Step i.
    2044             :         // Sadly, because someone could have overridden
    2045             :         // "resolve" on the canonical Promise constructor.
    2046           0 :         RootedValue nextPromise(cx);
    2047           0 :         RootedValue staticResolve(cx);
    2048           0 :         if (!GetProperty(cx, C, CVal, cx->names().resolve, &staticResolve))
    2049           0 :             return false;
    2050             : 
    2051           0 :         FixedInvokeArgs<1> resolveArgs(cx);
    2052           0 :         resolveArgs[0].set(nextValue);
    2053         690 :         if (!Call(cx, staticResolve, CVal, resolveArgs, &nextPromise))
    2054             :             return false;
    2055             : 
    2056             :         // Step j.
    2057         460 :         RootedFunction resolveFunc(cx, NewNativeFunction(cx, PromiseAllResolveElementFunction,
    2058             :                                                          1, nullptr,
    2059             :                                                          gc::AllocKind::FUNCTION_EXTENDED,
    2060           0 :                                                          GenericObject));
    2061           0 :         if (!resolveFunc)
    2062           0 :             return false;
    2063             : 
    2064             :         // Steps k,m,n.
    2065         460 :         resolveFunc->setExtendedSlot(PromiseAllResolveElementFunctionSlot_Data, dataHolderVal);
    2066             : 
    2067             :         // Step l.
    2068           0 :         resolveFunc->setExtendedSlot(PromiseAllResolveElementFunctionSlot_ElementIndex,
    2069         690 :                                      Int32Value(index));
    2070             : 
    2071             :         // Steps o-p.
    2072         230 :         dataHolder->increaseRemainingCount();
    2073             : 
    2074             :         // Step q.
    2075           0 :         RootedValue resolveFunVal(cx, ObjectValue(*resolveFunc));
    2076           0 :         if (!BlockOnPromise(cx, nextPromise, promiseObj, resolveFunVal, rejectFunVal))
    2077           0 :             return false;
    2078             : 
    2079             :         // Step r.
    2080           0 :         index++;
    2081         230 :         MOZ_ASSERT(index > 0);
    2082             :     }
    2083             : }
    2084             : 
    2085             : // ES2016, 25.4.4.1.2.
    2086             : static bool
    2087         229 : PromiseAllResolveElementFunction(JSContext* cx, unsigned argc, Value* vp)
    2088             : {
    2089         229 :     CallArgs args = CallArgsFromVp(argc, vp);
    2090             : 
    2091           0 :     RootedFunction resolve(cx, &args.callee().as<JSFunction>());
    2092         458 :     RootedValue xVal(cx, args.get(0));
    2093             : 
    2094             :     // Step 1.
    2095         458 :     RootedValue dataVal(cx, resolve->getExtendedSlot(PromiseAllResolveElementFunctionSlot_Data));
    2096             : 
    2097             :     // Step 2.
    2098             :     // We use the existence of the data holder as a signal for whether the
    2099             :     // Promise was already resolved. Upon resolution, it's reset to
    2100             :     // `undefined`.
    2101           0 :     if (dataVal.isUndefined()) {
    2102           0 :         args.rval().setUndefined();
    2103           0 :         return true;
    2104             :     }
    2105             : 
    2106         458 :     Rooted<PromiseAllDataHolder*> data(cx, &dataVal.toObject().as<PromiseAllDataHolder>());
    2107             : 
    2108             :     // Step 3.
    2109         458 :     resolve->setExtendedSlot(PromiseAllResolveElementFunctionSlot_Data, UndefinedValue());
    2110             : 
    2111             :     // Step 4.
    2112           0 :     int32_t index = resolve->getExtendedSlot(PromiseAllResolveElementFunctionSlot_ElementIndex)
    2113         229 :                     .toInt32();
    2114             : 
    2115             :     // Step 5.
    2116           0 :     RootedValue valuesVal(cx, data->valuesArray());
    2117           0 :     RootedObject valuesObj(cx, &valuesVal.toObject());
    2118           0 :     bool valuesListIsWrapped = false;
    2119           0 :     if (IsWrapper(valuesObj)) {
    2120           0 :         valuesListIsWrapped = true;
    2121             :         // See comment for PerformPromiseAll, step 3 for why we unwrap here.
    2122           0 :         valuesObj = UncheckedUnwrap(valuesObj);
    2123             :     }
    2124           0 :     if (JS_IsDeadWrapper(valuesObj)) {
    2125           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
    2126           0 :         return false;
    2127             :     }
    2128         458 :     RootedNativeObject values(cx, &valuesObj->as<NativeObject>());
    2129             : 
    2130             :     // Step 6 (moved under step 10).
    2131             :     // Step 7 (moved to step 9).
    2132             : 
    2133             :     // Step 8.
    2134             :     // The index is guaranteed to be initialized to `undefined`.
    2135           0 :     if (valuesListIsWrapped) {
    2136           0 :         AutoRealm ar(cx, values);
    2137           0 :         if (!cx->compartment()->wrap(cx, &xVal))
    2138           0 :             return false;
    2139             :     }
    2140         458 :     values->setDenseElement(index, xVal);
    2141             : 
    2142             :     // Steps 7,9.
    2143         229 :     uint32_t remainingCount = data->decreaseRemainingCount();
    2144             : 
    2145             :     // Step 10.
    2146         229 :     if (remainingCount == 0) {
    2147             :         // Step 10.a. (Omitted, happened in PerformPromiseAll.)
    2148             :         // Step 10.b.
    2149             : 
    2150             :         // Step 6 (Adapted to work with PromiseAllDataHolder's layout).
    2151           0 :         RootedObject resolveAllFun(cx, data->resolveObj());
    2152           0 :         RootedObject promiseObj(cx, data->promiseObj());
    2153           1 :         if (!RunResolutionFunction(cx, resolveAllFun, valuesVal, ResolveMode, promiseObj))
    2154           0 :             return false;
    2155             :     }
    2156             : 
    2157             :     // Step 11.
    2158           0 :     args.rval().setUndefined();
    2159         229 :     return true;
    2160             : }
    2161             : 
    2162             : static MOZ_MUST_USE bool PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator,
    2163             :                                             HandleObject C, HandleObject promiseObj,
    2164             :                                             HandleObject resolve, HandleObject reject,
    2165             :                                             bool* done);
    2166             : 
    2167             : // ES2016, 25.4.4.3.
    2168             : static bool
    2169           8 : Promise_static_race(JSContext* cx, unsigned argc, Value* vp)
    2170             : {
    2171           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2172          16 :     RootedValue iterable(cx, args.get(0));
    2173             : 
    2174             :     // Step 2 (reordered).
    2175           0 :     RootedValue CVal(cx, args.thisv());
    2176           8 :     if (!CVal.isObject()) {
    2177             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
    2178           0 :                                   "Receiver of Promise.race call");
    2179           0 :         return false;
    2180             :     }
    2181             : 
    2182             :     // Step 1.
    2183          16 :     RootedObject C(cx, &CVal.toObject());
    2184             : 
    2185             :     // Step 3.
    2186           0 :     RootedObject resultPromise(cx);
    2187           0 :     RootedObject resolve(cx);
    2188           0 :     RootedObject reject(cx);
    2189          32 :     if (!NewPromiseCapability(cx, C, &resultPromise, &resolve, &reject, false))
    2190             :         return false;
    2191             : 
    2192             :     // Steps 4-5.
    2193           0 :     JS::ForOfIterator iter(cx);
    2194           0 :     if (!iter.init(iterable, JS::ForOfIterator::AllowNonIterable))
    2195           0 :         return AbruptRejectPromise(cx, args, resultPromise, reject);
    2196             : 
    2197           8 :     if (!iter.valueIsIterable()) {
    2198             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE,
    2199           0 :                                   "Argument of Promise.race");
    2200           0 :         return AbruptRejectPromise(cx, args, resultPromise, reject);
    2201             :     }
    2202             : 
    2203             :     // Step 6 (implicit).
    2204             : 
    2205             :     // Step 7.
    2206             :     bool done;
    2207          32 :     bool result = PerformPromiseRace(cx, iter, C, resultPromise, resolve, reject, &done);
    2208             : 
    2209             :     // Step 8.
    2210           8 :     if (!result) {
    2211             :         // Step 8.a.
    2212           0 :         if (!done)
    2213           0 :             iter.closeThrow();
    2214             : 
    2215             :         // Step 8.b.
    2216           0 :         return AbruptRejectPromise(cx, args, resultPromise, reject);
    2217             :     }
    2218             : 
    2219             :     // Step 9.
    2220           0 :     args.rval().setObject(*resultPromise);
    2221           8 :     return true;
    2222             : }
    2223             : 
    2224             : // ES2016, 25.4.4.3.1.
    2225             : static MOZ_MUST_USE bool
    2226           8 : PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
    2227             :                    HandleObject promiseObj, HandleObject resolve, HandleObject reject,
    2228             :                    bool* done)
    2229             : {
    2230           0 :     *done = false;
    2231           0 :     MOZ_ASSERT(C->isConstructor());
    2232          24 :     RootedValue CVal(cx, ObjectValue(*C));
    2233             : 
    2234           0 :     RootedValue nextValue(cx);
    2235           0 :     RootedValue resolveFunVal(cx, ObjectValue(*resolve));
    2236          24 :     RootedValue rejectFunVal(cx, ObjectValue(*reject));
    2237             : 
    2238             :     while (true) {
    2239             :         // Steps a-c, e-g.
    2240          20 :         if (!iterator.next(&nextValue, done)) {
    2241             :             // Steps b, f.
    2242           0 :             *done = true;
    2243             : 
    2244             :             // Steps c, g.
    2245           8 :             return false;
    2246             :         }
    2247             : 
    2248             :         // Step d.
    2249          20 :         if (*done) {
    2250             :             // Step d.i (implicit).
    2251             : 
    2252             :             // Step d.ii.
    2253             :             return true;
    2254             :         }
    2255             : 
    2256             :         // Step h.
    2257             :         // Sadly, because someone could have overridden
    2258             :         // "resolve" on the canonical Promise constructor.
    2259           0 :         RootedValue nextPromise(cx);
    2260           0 :         RootedValue staticResolve(cx);
    2261           0 :         if (!GetProperty(cx, C, CVal, cx->names().resolve, &staticResolve))
    2262           0 :             return false;
    2263             : 
    2264           0 :         FixedInvokeArgs<1> resolveArgs(cx);
    2265           0 :         resolveArgs[0].set(nextValue);
    2266          36 :         if (!Call(cx, staticResolve, CVal, resolveArgs, &nextPromise))
    2267             :             return false;
    2268             : 
    2269             :         // Step i.
    2270          36 :         if (!BlockOnPromise(cx, nextPromise, promiseObj, resolveFunVal, rejectFunVal))
    2271             :             return false;
    2272             :     }
    2273             : 
    2274             :     MOZ_ASSERT_UNREACHABLE("Shouldn't reach the end of PerformPromiseRace");
    2275             : }
    2276             : 
    2277             : 
    2278             : // ES2016, Sub-steps of 25.4.4.4 and 25.4.4.5.
    2279             : static MOZ_MUST_USE JSObject*
    2280         335 : CommonStaticResolveRejectImpl(JSContext* cx, HandleValue thisVal, HandleValue argVal,
    2281             :                               ResolutionMode mode)
    2282             : {
    2283             :     // Steps 1-2.
    2284         335 :     if (!thisVal.isObject()) {
    2285             :         const char* msg = mode == ResolveMode
    2286           0 :                           ? "Receiver of Promise.resolve call"
    2287           0 :                           : "Receiver of Promise.reject call";
    2288           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, msg);
    2289           0 :         return nullptr;
    2290             :     }
    2291         670 :     RootedObject C(cx, &thisVal.toObject());
    2292             : 
    2293             :     // Step 3 of Resolve.
    2294           0 :     if (mode == ResolveMode && argVal.isObject()) {
    2295           0 :         RootedObject xObj(cx, &argVal.toObject());
    2296           0 :         bool isPromise = false;
    2297         496 :         if (xObj->is<PromiseObject>()) {
    2298             :             isPromise = true;
    2299          50 :         } else if (IsWrapper(xObj)) {
    2300             :             // Treat instances of Promise from other compartments as Promises
    2301             :             // here, too.
    2302             :             // It's important to do the GetProperty for the `constructor`
    2303             :             // below through the wrapper, because wrappers can change the
    2304             :             // outcome, so instead of unwrapping and then performing the
    2305             :             // GetProperty, just check here and then operate on the original
    2306             :             // object again.
    2307           0 :             RootedObject unwrappedObject(cx, CheckedUnwrap(xObj));
    2308           0 :             if (unwrappedObject && unwrappedObject->is<PromiseObject>())
    2309           1 :                 isPromise = true;
    2310             :         }
    2311           0 :         if (isPromise) {
    2312           0 :             RootedValue ctorVal(cx);
    2313           0 :             if (!GetProperty(cx, xObj, xObj, cx->names().constructor, &ctorVal))
    2314           0 :                 return nullptr;
    2315           0 :             if (ctorVal == thisVal)
    2316         198 :                 return xObj;
    2317             :         }
    2318             :     }
    2319             : 
    2320             :     // Step 4 of Resolve, 3 of Reject.
    2321           0 :     RootedObject promise(cx);
    2322           0 :     RootedObject resolveFun(cx);
    2323           0 :     RootedObject rejectFun(cx);
    2324         548 :     if (!NewPromiseCapability(cx, C, &promise, &resolveFun, &rejectFun, true))
    2325             :         return nullptr;
    2326             : 
    2327             :     // Step 5 of Resolve, 4 of Reject.
    2328         274 :     if (!RunResolutionFunction(cx, mode == ResolveMode ? resolveFun : rejectFun, argVal, mode,
    2329             :                                promise))
    2330             :     {
    2331             :         return nullptr;
    2332             :     }
    2333             : 
    2334             :     // Step 6 of Resolve, 4 of Reject.
    2335         137 :     return promise;
    2336             : }
    2337             : 
    2338             : MOZ_MUST_USE JSObject*
    2339           0 : js::PromiseResolve(JSContext* cx, HandleObject constructor, HandleValue value)
    2340             : {
    2341           0 :     RootedValue C(cx, ObjectValue(*constructor));
    2342           0 :     return CommonStaticResolveRejectImpl(cx, C, value, ResolveMode);
    2343             : }
    2344             : 
    2345             : /**
    2346             :  * ES2016, 25.4.4.4, Promise.reject.
    2347             :  */
    2348             : static bool
    2349           0 : Promise_reject(JSContext* cx, unsigned argc, Value* vp)
    2350             : {
    2351           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2352           0 :     RootedValue thisVal(cx, args.thisv());
    2353           0 :     RootedValue argVal(cx, args.get(0));
    2354           0 :     JSObject* result = CommonStaticResolveRejectImpl(cx, thisVal, argVal, RejectMode);
    2355           0 :     if (!result)
    2356             :         return false;
    2357           0 :     args.rval().setObject(*result);
    2358           0 :     return true;
    2359             : }
    2360             : 
    2361             : /**
    2362             :  * Unforgeable version of ES2016, 25.4.4.4, Promise.reject.
    2363             :  */
    2364             : /* static */ JSObject*
    2365           0 : PromiseObject::unforgeableReject(JSContext* cx, HandleValue value)
    2366             : {
    2367           0 :     RootedObject promiseCtor(cx, JS::GetPromiseConstructor(cx));
    2368           0 :     if (!promiseCtor)
    2369             :         return nullptr;
    2370           0 :     RootedValue cVal(cx, ObjectValue(*promiseCtor));
    2371           0 :     return CommonStaticResolveRejectImpl(cx, cVal, value, RejectMode);
    2372             : }
    2373             : 
    2374             : /**
    2375             :  * ES2016, 25.4.4.5, Promise.resolve.
    2376             :  */
    2377             : static bool
    2378         334 : Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp)
    2379             : {
    2380           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2381           0 :     RootedValue thisVal(cx, args.thisv());
    2382           0 :     RootedValue argVal(cx, args.get(0));
    2383           0 :     JSObject* result = CommonStaticResolveRejectImpl(cx, thisVal, argVal, ResolveMode);
    2384         334 :     if (!result)
    2385             :         return false;
    2386           0 :     args.rval().setObject(*result);
    2387         334 :     return true;
    2388             : }
    2389             : 
    2390             : /**
    2391             :  * Unforgeable version of ES2016, 25.4.4.5, Promise.resolve.
    2392             :  */
    2393             : /* static */ JSObject*
    2394           1 : PromiseObject::unforgeableResolve(JSContext* cx, HandleValue value)
    2395             : {
    2396           0 :     RootedObject promiseCtor(cx, JS::GetPromiseConstructor(cx));
    2397           1 :     if (!promiseCtor)
    2398             :         return nullptr;
    2399           0 :     RootedValue cVal(cx, ObjectValue(*promiseCtor));
    2400           1 :     return CommonStaticResolveRejectImpl(cx, cVal, value, ResolveMode);
    2401             : }
    2402             : 
    2403             : /**
    2404             :  * ES2016, 25.4.4.6 get Promise [ @@species ]
    2405             :  */
    2406             : static bool
    2407           4 : Promise_static_species(JSContext* cx, unsigned argc, Value* vp)
    2408             : {
    2409           4 :     CallArgs args = CallArgsFromVp(argc, vp);
    2410             : 
    2411             :     // Step 1: Return the this value.
    2412           0 :     args.rval().set(args.thisv());
    2413           4 :     return true;
    2414             : }
    2415             : 
    2416             : // ES2016, 25.4.5.1, implemented in Promise.js.
    2417             : 
    2418             : static PromiseReactionRecord*
    2419        3143 : NewReactionRecord(JSContext* cx, HandleObject resultPromise, HandleValue onFulfilled,
    2420             :                   HandleValue onRejected, HandleObject resolve, HandleObject reject,
    2421             :                   HandleObject incumbentGlobalObject)
    2422             : {
    2423             :     // Either of the following conditions must be met:
    2424             :     //   * resultPromise is a PromiseObject
    2425             :     //   * resolve and reject are callable
    2426             :     // except for Async Generator, there resultPromise can be nullptr.
    2427           0 :     MOZ_ASSERT_IF(resultPromise && !resultPromise->is<PromiseObject>(), resolve);
    2428           0 :     MOZ_ASSERT_IF(resultPromise && !resultPromise->is<PromiseObject>(), IsCallable(resolve));
    2429           0 :     MOZ_ASSERT_IF(resultPromise && !resultPromise->is<PromiseObject>(), reject);
    2430        9171 :     MOZ_ASSERT_IF(resultPromise && !resultPromise->is<PromiseObject>(), IsCallable(reject));
    2431             : 
    2432           0 :     Rooted<PromiseReactionRecord*> reaction(cx, NewObjectWithClassProto<PromiseReactionRecord>(cx));
    2433        3143 :     if (!reaction)
    2434             :         return nullptr;
    2435             : 
    2436           0 :     assertSameCompartment(cx, resultPromise);
    2437           0 :     assertSameCompartment(cx, onFulfilled);
    2438           0 :     assertSameCompartment(cx, onRejected);
    2439           0 :     assertSameCompartment(cx, resolve);
    2440           0 :     assertSameCompartment(cx, reject);
    2441        3143 :     assertSameCompartment(cx, incumbentGlobalObject);
    2442             : 
    2443           0 :     reaction->setFixedSlot(ReactionRecordSlot_Promise, ObjectOrNullValue(resultPromise));
    2444           0 :     reaction->setFixedSlot(ReactionRecordSlot_Flags, Int32Value(0));
    2445           0 :     reaction->setFixedSlot(ReactionRecordSlot_OnFulfilled, onFulfilled);
    2446           0 :     reaction->setFixedSlot(ReactionRecordSlot_OnRejected, onRejected);
    2447           0 :     reaction->setFixedSlot(ReactionRecordSlot_Resolve, ObjectOrNullValue(resolve));
    2448           0 :     reaction->setFixedSlot(ReactionRecordSlot_Reject, ObjectOrNullValue(reject));
    2449           0 :     reaction->setFixedSlot(ReactionRecordSlot_IncumbentGlobalObject,
    2450        9429 :                            ObjectOrNullValue(incumbentGlobalObject));
    2451             : 
    2452        3143 :     return reaction;
    2453             : }
    2454             : 
    2455             : static bool
    2456        2071 : IsPromiseSpecies(JSContext* cx, JSFunction* species)
    2457             : {
    2458        2071 :     return species->maybeNative() == Promise_static_species;
    2459             : }
    2460             : 
    2461             : // ES2016, 25.4.5.3., steps 3-5.
    2462             : MOZ_MUST_USE bool
    2463        1834 : js::OriginalPromiseThen(JSContext* cx, Handle<PromiseObject*> promise,
    2464             :                         HandleValue onFulfilled, HandleValue onRejected,
    2465             :                         MutableHandleObject dependent, CreateDependentPromise createDependent)
    2466             : {
    2467           0 :     RootedObject promiseObj(cx, promise);
    2468           0 :     if (promise->compartment() != cx->compartment()) {
    2469           4 :         if (!cx->compartment()->wrap(cx, &promiseObj))
    2470             :             return false;
    2471             :     }
    2472             : 
    2473           0 :     RootedObject resultPromise(cx);
    2474           0 :     RootedObject resolve(cx);
    2475        3668 :     RootedObject reject(cx);
    2476             : 
    2477        1834 :     if (createDependent != CreateDependentPromise::Never) {
    2478             :         // Step 3.
    2479           0 :         RootedObject C(cx, SpeciesConstructor(cx, promiseObj, JSProto_Promise, IsPromiseSpecies));
    2480           0 :         if (!C)
    2481           0 :             return false;
    2482             : 
    2483           0 :         if (createDependent == CreateDependentPromise::Always ||
    2484         132 :             !IsNativeFunction(C, PromiseConstructor))
    2485             :         {
    2486             :             // Step 4.
    2487        6812 :             if (!NewPromiseCapability(cx, C, &resultPromise, &resolve, &reject, true))
    2488             :                 return false;
    2489             :         }
    2490             :     }
    2491             : 
    2492             :     // Step 5.
    2493        5502 :     if (!PerformPromiseThen(cx, promise, onFulfilled, onRejected, resultPromise, resolve, reject))
    2494             :         return false;
    2495             : 
    2496           0 :     dependent.set(resultPromise);
    2497        1834 :     return true;
    2498             : }
    2499             : 
    2500             : static MOZ_MUST_USE bool PerformPromiseThenWithReaction(JSContext* cx,
    2501             :                                                         Handle<PromiseObject*> promise,
    2502             :                                                         Handle<PromiseReactionRecord*> reaction);
    2503             : 
    2504             : // Some async/await functions are implemented here instead of
    2505             : // js/src/builtin/AsyncFunction.cpp, to call Promise internal functions.
    2506             : 
    2507             : // ES 2018 draft 14.6.11 and 14.7.14 step 1.
    2508             : MOZ_MUST_USE PromiseObject*
    2509         953 : js::CreatePromiseObjectForAsync(JSContext* cx, HandleValue generatorVal)
    2510             : {
    2511             :     // Step 1.
    2512           0 :     PromiseObject* promise = CreatePromiseObjectWithoutResolutionFunctions(cx);
    2513         953 :     if (!promise)
    2514             :         return nullptr;
    2515             : 
    2516           0 :     AddPromiseFlags(*promise, PROMISE_FLAG_ASYNC);
    2517           0 :     promise->setFixedSlot(PromiseSlot_AwaitGenerator, generatorVal);
    2518         953 :     return promise;
    2519             : }
    2520             : 
    2521             : bool
    2522           0 : js::IsPromiseForAsync(JSObject* promise)
    2523             : {
    2524           0 :     return promise->is<PromiseObject>() &&
    2525           0 :            PromiseHasAnyFlag(promise->as<PromiseObject>(), PROMISE_FLAG_ASYNC);
    2526             : }
    2527             : 
    2528             : // ES 2018 draft 25.5.5.2 steps 3.f, 3.g.
    2529             : MOZ_MUST_USE bool
    2530          20 : js::AsyncFunctionThrown(JSContext* cx, Handle<PromiseObject*> resultPromise)
    2531             : {
    2532             :     // Step 3.f.
    2533           0 :     RootedValue exc(cx);
    2534          20 :     if (!MaybeGetAndClearException(cx, &exc))
    2535             :         return false;
    2536             : 
    2537          40 :     if (!RejectMaybeWrappedPromise(cx, resultPromise, exc))
    2538             :         return false;
    2539             : 
    2540             :     // Step 3.g.
    2541          20 :     return true;
    2542             : }
    2543             : 
    2544             : // ES 2018 draft 25.5.5.2 steps 3.d-e, 3.g.
    2545             : MOZ_MUST_USE bool
    2546         900 : js::AsyncFunctionReturned(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value)
    2547             : {
    2548             :     // Steps 3.d-e.
    2549         900 :     if (!ResolvePromiseInternal(cx, resultPromise, value))
    2550             :         return false;
    2551             : 
    2552             :     // Step 3.g.
    2553         900 :     return true;
    2554             : }
    2555             : 
    2556             : // Helper function that performs the equivalent steps as
    2557             : // Async Iteration proposal 4.1 Await steps 2-3, 6-9 or similar.
    2558             : template <typename T>
    2559             : static MOZ_MUST_USE bool
    2560        1067 : InternalAwait(JSContext* cx, HandleValue value, HandleObject resultPromise,
    2561             :               HandleValue onFulfilled, HandleValue onRejected, T extraStep)
    2562             : {
    2563           0 :     MOZ_ASSERT(onFulfilled.isNumber() || onFulfilled.isObject());
    2564        1067 :     MOZ_ASSERT(onRejected.isNumber() || onRejected.isObject());
    2565             : 
    2566             :     // Step 2.
    2567           0 :     Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
    2568        1067 :     if (!promise)
    2569             :         return false;
    2570             : 
    2571             :     // Step 3.
    2572        1067 :     if (!ResolvePromiseInternal(cx, promise, value))
    2573             :         return false;
    2574             : 
    2575           0 :     RootedObject incumbentGlobal(cx);
    2576        1067 :     if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal))
    2577             :         return false;
    2578             : 
    2579             :     // Step 7-8.
    2580        4268 :     Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise,
    2581             :                                                                   onFulfilled, onRejected,
    2582             :                                                                   nullptr, nullptr,
    2583           0 :                                                                   incumbentGlobal));
    2584        1067 :     if (!reaction)
    2585             :         return false;
    2586             : 
    2587             :     // Step 6.
    2588        2134 :     extraStep(reaction);
    2589             : 
    2590             :     // Step 9.
    2591        2134 :     return PerformPromiseThenWithReaction(cx, promise, reaction);
    2592             : }
    2593             : 
    2594             : // ES 2018 draft 25.5.5.3 steps 2-10.
    2595             : MOZ_MUST_USE bool
    2596        1067 : js::AsyncFunctionAwait(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value)
    2597             : {
    2598             :     // Steps 4-5.
    2599           0 :     RootedValue onFulfilled(cx, Int32Value(PromiseHandlerAsyncFunctionAwaitedFulfilled));
    2600        2134 :     RootedValue onRejected(cx, Int32Value(PromiseHandlerAsyncFunctionAwaitedRejected));
    2601             : 
    2602             :     // Steps 2-3, 6-10.
    2603             :     auto extra = [](Handle<PromiseReactionRecord*> reaction) {
    2604        1067 :         reaction->setIsAsyncFunction();
    2605             :     };
    2606        4268 :     return InternalAwait(cx, value, resultPromise, onFulfilled, onRejected, extra);
    2607             : }
    2608             : 
    2609             : // Async Iteration proposal 4.1 Await steps 2-9.
    2610             : MOZ_MUST_USE bool
    2611           0 : js::AsyncGeneratorAwait(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
    2612             :                         HandleValue value)
    2613             : {
    2614             :     // Steps 4-5.
    2615           0 :     RootedValue onFulfilled(cx, Int32Value(PromiseHandlerAsyncGeneratorAwaitedFulfilled));
    2616           0 :     RootedValue onRejected(cx, Int32Value(PromiseHandlerAsyncGeneratorAwaitedRejected));
    2617             : 
    2618             :     // Steps 2-3, 6-9.
    2619             :     auto extra = [&](Handle<PromiseReactionRecord*> reaction) {
    2620           0 :         reaction->setIsAsyncGenerator(asyncGenObj);
    2621           0 :     };
    2622           0 :     return InternalAwait(cx, value, nullptr, onFulfilled, onRejected, extra);
    2623             : }
    2624             : 
    2625             : // Async Iteration proposal 11.1.3.2.1 %AsyncFromSyncIteratorPrototype%.next
    2626             : // Async Iteration proposal 11.1.3.2.2 %AsyncFromSyncIteratorPrototype%.return
    2627             : // Async Iteration proposal 11.1.3.2.3 %AsyncFromSyncIteratorPrototype%.throw
    2628             : bool
    2629           0 : js::AsyncFromSyncIteratorMethod(JSContext* cx, CallArgs& args, CompletionKind completionKind)
    2630             : {
    2631             :     // Step 1.
    2632           0 :     RootedValue thisVal(cx, args.thisv());
    2633             : 
    2634             :     // Step 2.
    2635           0 :     RootedObject resultPromise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
    2636           0 :     if (!resultPromise)
    2637             :         return false;
    2638             : 
    2639             :     // Step 3.
    2640           0 :     if (!thisVal.isObject() || !thisVal.toObject().is<AsyncFromSyncIteratorObject>()) {
    2641             :         // NB: See https://github.com/tc39/proposal-async-iteration/issues/105
    2642             :         // for why this check shouldn't be necessary as long as we can ensure
    2643             :         // the Async-from-Sync iterator can't be accessed directly by user
    2644             :         // code.
    2645             : 
    2646             :         // Step 3.a.
    2647           0 :         RootedValue badGeneratorError(cx);
    2648           0 :         if (!GetTypeError(cx, JSMSG_NOT_AN_ASYNC_ITERATOR, &badGeneratorError))
    2649             :             return false;
    2650             : 
    2651             :         // Step 3.b.
    2652           0 :         if (!RejectMaybeWrappedPromise(cx, resultPromise, badGeneratorError))
    2653             :             return false;
    2654             : 
    2655             :         // Step 3.c.
    2656           0 :         args.rval().setObject(*resultPromise);
    2657           0 :         return true;
    2658             :     }
    2659             : 
    2660             :     Rooted<AsyncFromSyncIteratorObject*> asyncIter(
    2661           0 :         cx, &thisVal.toObject().as<AsyncFromSyncIteratorObject>());
    2662             : 
    2663             :     // Step 4.
    2664           0 :     RootedObject iter(cx, asyncIter->iterator());
    2665             : 
    2666           0 :     RootedValue resultVal(cx);
    2667           0 :     RootedValue func(cx);
    2668           0 :     if (completionKind == CompletionKind::Normal) {
    2669             :         // 11.1.3.2.1 steps 5-6 (partially).
    2670           0 :         func.set(asyncIter->nextMethod());
    2671           0 :     } else if (completionKind == CompletionKind::Return) {
    2672             :         // 11.1.3.2.2 steps 5-6.
    2673           0 :         if (!GetProperty(cx, iter, iter, cx->names().return_, &func))
    2674           0 :             return AbruptRejectPromise(cx, args, resultPromise, nullptr);
    2675             : 
    2676             :         // Step 7.
    2677           0 :         if (func.isNullOrUndefined()) {
    2678             :             // Step 7.a.
    2679           0 :             RootedObject resultObj(cx, CreateIterResultObject(cx, args.get(0), true));
    2680           0 :             if (!resultObj)
    2681           0 :                 return AbruptRejectPromise(cx, args, resultPromise, nullptr);
    2682             : 
    2683           0 :             RootedValue resultVal(cx, ObjectValue(*resultObj));
    2684             : 
    2685             :             // Step 7.b.
    2686           0 :             if (!ResolvePromiseInternal(cx, resultPromise, resultVal))
    2687           0 :                 return AbruptRejectPromise(cx, args, resultPromise, nullptr);
    2688             : 
    2689             :             // Step 7.c.
    2690           0 :             args.rval().setObject(*resultPromise);
    2691           0 :             return true;
    2692             :         }
    2693             :     } else {
    2694             :         // 11.1.3.2.3 steps 5-6.
    2695           0 :         MOZ_ASSERT(completionKind == CompletionKind::Throw);
    2696           0 :         if (!GetProperty(cx, iter, iter, cx->names().throw_, &func))
    2697           0 :             return AbruptRejectPromise(cx, args, resultPromise, nullptr);
    2698             : 
    2699             :         // Step 7.
    2700           0 :         if (func.isNullOrUndefined()) {
    2701             :             // Step 7.a.
    2702           0 :             if (!RejectMaybeWrappedPromise(cx, resultPromise, args.get(0)))
    2703           0 :                 return AbruptRejectPromise(cx, args, resultPromise, nullptr);
    2704             : 
    2705             :             // Step 7.b.
    2706           0 :             args.rval().setObject(*resultPromise);
    2707           0 :             return true;
    2708             :         }
    2709             :     }
    2710             : 
    2711             :     // 11.1.3.2.1 steps 5-6 (partially).
    2712             :     // 11.1.3.2.2, 11.1.3.2.3 steps 8-9.
    2713           0 :     RootedValue iterVal(cx, ObjectValue(*iter));
    2714           0 :     FixedInvokeArgs<1> args2(cx);
    2715           0 :     args2[0].set(args.get(0));
    2716           0 :     if (!js::Call(cx, func, iterVal, args2, &resultVal))
    2717           0 :         return AbruptRejectPromise(cx, args, resultPromise, nullptr);
    2718             : 
    2719             :     // 11.1.3.2.1 steps 5-6 (partially).
    2720             :     // 11.1.3.2.2, 11.1.3.2.3 steps 10.
    2721           0 :     if (!resultVal.isObject()) {
    2722             :         CheckIsObjectKind kind;
    2723           0 :         switch (completionKind) {
    2724             :           case CompletionKind::Normal:
    2725           0 :             kind = CheckIsObjectKind::IteratorNext;
    2726           0 :             break;
    2727             :           case CompletionKind::Throw:
    2728           0 :             kind = CheckIsObjectKind::IteratorThrow;
    2729           0 :             break;
    2730             :           case CompletionKind::Return:
    2731           0 :             kind = CheckIsObjectKind::IteratorReturn;
    2732           0 :             break;
    2733             :         }
    2734           0 :         MOZ_ALWAYS_FALSE(ThrowCheckIsObject(cx, kind));
    2735           0 :         return AbruptRejectPromise(cx, args, resultPromise, nullptr);
    2736             :     }
    2737             : 
    2738           0 :     RootedObject resultObj(cx, &resultVal.toObject());
    2739             : 
    2740             :     // Following step numbers are for 11.1.3.2.1.
    2741             :     // For 11.1.3.2.2 and 11.1.3.2.3, steps 7-16 corresponds to steps 11-20.
    2742             : 
    2743             :     // Steps 7-8.
    2744           0 :     RootedValue doneVal(cx);
    2745           0 :     if (!GetProperty(cx, resultObj, resultObj, cx->names().done, &doneVal))
    2746           0 :         return AbruptRejectPromise(cx, args, resultPromise, nullptr);
    2747           0 :     bool done = ToBoolean(doneVal);
    2748             : 
    2749             :     // Steps 9-10.
    2750           0 :     RootedValue value(cx);
    2751           0 :     if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value))
    2752           0 :         return AbruptRejectPromise(cx, args, resultPromise, nullptr);
    2753             : 
    2754             :     // Steps 13-14.
    2755           0 :     RootedValue onFulfilled(cx, Int32Value(done
    2756             :                                            ? PromiseHandlerAsyncFromSyncIteratorValueUnwrapDone
    2757           0 :                                            : PromiseHandlerAsyncFromSyncIteratorValueUnwrapNotDone));
    2758           0 :     RootedValue onRejected(cx, Int32Value(PromiseHandlerThrower));
    2759             : 
    2760             :     // Steps 11-12, 15.
    2761             :     auto extra = [](Handle<PromiseReactionRecord*> reaction) {
    2762             :     };
    2763           0 :     if (!InternalAwait(cx, value, resultPromise, onFulfilled, onRejected, extra))
    2764             :         return false;
    2765             : 
    2766             :     // Step 16.
    2767           0 :     args.rval().setObject(*resultPromise);
    2768           0 :     return true;
    2769             : }
    2770             : 
    2771             : enum class ResumeNextKind {
    2772             :     Enqueue, Reject, Resolve
    2773             : };
    2774             : 
    2775             : static MOZ_MUST_USE bool
    2776             : AsyncGeneratorResumeNext(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
    2777             :                          ResumeNextKind kind, HandleValue valueOrException = UndefinedHandleValue,
    2778             :                          bool done = false);
    2779             : 
    2780             : // Async Iteration proposal 11.4.3.3.
    2781             : MOZ_MUST_USE bool
    2782           0 : js::AsyncGeneratorResolve(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
    2783             :                           HandleValue value, bool done)
    2784             : {
    2785           0 :     return AsyncGeneratorResumeNext(cx, asyncGenObj, ResumeNextKind::Resolve, value, done);
    2786             : }
    2787             : 
    2788             : // Async Iteration proposal 11.4.3.4.
    2789             : MOZ_MUST_USE bool
    2790           0 : js::AsyncGeneratorReject(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
    2791             :                          HandleValue exception)
    2792             : {
    2793           0 :     return AsyncGeneratorResumeNext(cx, asyncGenObj, ResumeNextKind::Reject, exception);
    2794             : }
    2795             : 
    2796             : // Async Iteration proposal 11.4.3.5.
    2797             : static MOZ_MUST_USE bool
    2798           0 : AsyncGeneratorResumeNext(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
    2799             :                          ResumeNextKind kind,
    2800             :                          HandleValue valueOrException_ /* = UndefinedHandleValue */,
    2801             :                          bool done /* = false */)
    2802             : {
    2803           0 :     RootedValue valueOrException(cx, valueOrException_);
    2804             : 
    2805             :     while (true) {
    2806           0 :         switch (kind) {
    2807             :           case ResumeNextKind::Enqueue:
    2808             :             // No further action required.
    2809             :             break;
    2810             :           case ResumeNextKind::Reject: {
    2811             :             // 11.4.3.4 AsyncGeneratorReject ( generator, exception )
    2812           0 :             HandleValue exception = valueOrException;
    2813             : 
    2814             :             // Step 1 (implicit).
    2815             : 
    2816             :             // Steps 2-3.
    2817           0 :             MOZ_ASSERT(!asyncGenObj->isQueueEmpty());
    2818             : 
    2819             :             // Step 4.
    2820             :             Rooted<AsyncGeneratorRequest*> request(
    2821           0 :                 cx, AsyncGeneratorObject::dequeueRequest(cx, asyncGenObj));
    2822           0 :             if (!request)
    2823           0 :                 return false;
    2824             : 
    2825             :             // Step 5.
    2826           0 :             RootedObject resultPromise(cx, request->promise());
    2827             : 
    2828           0 :             asyncGenObj->cacheRequest(request);
    2829             : 
    2830             :             // Step 6.
    2831           0 :             if (!RejectMaybeWrappedPromise(cx, resultPromise, exception))
    2832           0 :                 return false;
    2833             : 
    2834             :             // Steps 7-8.
    2835           0 :             break;
    2836             :           }
    2837             :           case ResumeNextKind::Resolve: {
    2838             :             // 11.4.3.3 AsyncGeneratorResolve ( generator, value, done )
    2839           0 :             HandleValue value = valueOrException;
    2840             : 
    2841             :             // Step 1 (implicit).
    2842             : 
    2843             :             // Steps 2-3.
    2844           0 :             MOZ_ASSERT(!asyncGenObj->isQueueEmpty());
    2845             : 
    2846             :             // Step 4.
    2847             :             Rooted<AsyncGeneratorRequest*> request(
    2848           0 :                 cx, AsyncGeneratorObject::dequeueRequest(cx, asyncGenObj));
    2849           0 :             if (!request)
    2850           0 :                 return false;
    2851             : 
    2852             :             // Step 5.
    2853           0 :             RootedObject resultPromise(cx, request->promise());
    2854             : 
    2855           0 :             asyncGenObj->cacheRequest(request);
    2856             : 
    2857             :             // Step 6.
    2858           0 :             RootedObject resultObj(cx, CreateIterResultObject(cx, value, done));
    2859           0 :             if (!resultObj)
    2860           0 :                 return false;
    2861             : 
    2862           0 :             RootedValue resultValue(cx, ObjectValue(*resultObj));
    2863             : 
    2864             :             // Step 7.
    2865           0 :             if (!ResolvePromiseInternal(cx, resultPromise, resultValue))
    2866           0 :                 return false;
    2867             : 
    2868             :             // Steps 8-9.
    2869           0 :             break;
    2870             :           }
    2871             :         }
    2872             : 
    2873             :         // Step 1 (implicit).
    2874             : 
    2875             :         // Steps 2-3.
    2876           0 :         MOZ_ASSERT(!asyncGenObj->isExecuting());
    2877             : 
    2878             :         // Step 4.
    2879           0 :         if (asyncGenObj->isAwaitingYieldReturn() || asyncGenObj->isAwaitingReturn())
    2880             :             return true;
    2881             : 
    2882             :         // Steps 5-6.
    2883           0 :         if (asyncGenObj->isQueueEmpty())
    2884             :             return true;
    2885             : 
    2886             :         // Steps 7-8.
    2887             :         Rooted<AsyncGeneratorRequest*> request(
    2888           0 :             cx, AsyncGeneratorObject::peekRequest(asyncGenObj));
    2889           0 :         if (!request)
    2890           0 :             return false;
    2891             : 
    2892             :         // Step 9.
    2893           0 :         CompletionKind completionKind = request->completionKind();
    2894             : 
    2895             :         // Step 10.
    2896           0 :         if (completionKind != CompletionKind::Normal) {
    2897             :             // Step 10.a.
    2898           0 :             if (asyncGenObj->isSuspendedStart())
    2899           0 :                 asyncGenObj->setCompleted();
    2900             : 
    2901             :             // Step 10.b.
    2902           0 :             if (asyncGenObj->isCompleted()) {
    2903           0 :                 RootedValue value(cx, request->completionValue());
    2904             : 
    2905             :                 // Step 10.b.i.
    2906           0 :                 if (completionKind == CompletionKind::Return) {
    2907             :                     // Steps 10.b.i.1.
    2908           0 :                     asyncGenObj->setAwaitingReturn();
    2909             : 
    2910             :                     // Steps 10.b.i.4-6 (reordered).
    2911             :                     static constexpr int32_t ResumeNextReturnFulfilled =
    2912             :                             PromiseHandlerAsyncGeneratorResumeNextReturnFulfilled;
    2913             :                     static constexpr int32_t ResumeNextReturnRejected =
    2914             :                             PromiseHandlerAsyncGeneratorResumeNextReturnRejected;
    2915             : 
    2916           0 :                     RootedValue onFulfilled(cx, Int32Value(ResumeNextReturnFulfilled));
    2917           0 :                     RootedValue onRejected(cx, Int32Value(ResumeNextReturnRejected));
    2918             : 
    2919             :                     // Steps 10.b.i.2-3, 7-10.
    2920             :                     auto extra = [&](Handle<PromiseReactionRecord*> reaction) {
    2921           0 :                         reaction->setIsAsyncGenerator(asyncGenObj);
    2922           0 :                     };
    2923           0 :                     return InternalAwait(cx, value, nullptr, onFulfilled, onRejected, extra);
    2924             :                 }
    2925             : 
    2926             :                 // Step 10.b.ii.1.
    2927           0 :                 MOZ_ASSERT(completionKind == CompletionKind::Throw);
    2928             : 
    2929             :                 // Steps 10.b.ii.2-3.
    2930           0 :                 kind = ResumeNextKind::Reject;
    2931           0 :                 valueOrException.set(value);
    2932             :                 // |done| is unused for ResumeNextKind::Reject.
    2933           0 :                 continue;
    2934             :             }
    2935           0 :         } else if (asyncGenObj->isCompleted()) {
    2936             :             // Step 11.
    2937           0 :             kind = ResumeNextKind::Resolve;
    2938           0 :             valueOrException.setUndefined();
    2939           0 :             done = true;
    2940           0 :             continue;
    2941             :         }
    2942             : 
    2943             :         // Step 12.
    2944           0 :         MOZ_ASSERT(asyncGenObj->isSuspendedStart() || asyncGenObj->isSuspendedYield());
    2945             : 
    2946             :         // Step 16 (reordered).
    2947           0 :         asyncGenObj->setExecuting();
    2948             : 
    2949           0 :         RootedValue argument(cx, request->completionValue());
    2950             : 
    2951           0 :         if (completionKind == CompletionKind::Return) {
    2952             :             // 11.4.3.7 AsyncGeneratorYield step 8.b-e.
    2953             :             // Since we don't have the place that handles return from yield
    2954             :             // inside the generator, handle the case here, with extra state
    2955             :             // State_AwaitingYieldReturn.
    2956           0 :             asyncGenObj->setAwaitingYieldReturn();
    2957             : 
    2958             :             static constexpr int32_t YieldReturnAwaitedFulfilled =
    2959             :                     PromiseHandlerAsyncGeneratorYieldReturnAwaitedFulfilled;
    2960             :             static constexpr int32_t YieldReturnAwaitedRejected =
    2961             :                     PromiseHandlerAsyncGeneratorYieldReturnAwaitedRejected;
    2962             : 
    2963           0 :             RootedValue onFulfilled(cx, Int32Value(YieldReturnAwaitedFulfilled));
    2964           0 :             RootedValue onRejected(cx, Int32Value(YieldReturnAwaitedRejected));
    2965             : 
    2966             :             auto extra = [&](Handle<PromiseReactionRecord*> reaction) {
    2967           0 :                 reaction->setIsAsyncGenerator(asyncGenObj);
    2968           0 :             };
    2969           0 :             return InternalAwait(cx, argument, nullptr, onFulfilled, onRejected, extra);
    2970             :         }
    2971             : 
    2972             :         // Steps 13-15, 17-21.
    2973           0 :         return AsyncGeneratorResume(cx, asyncGenObj, completionKind, argument);
    2974             :     }
    2975             : }
    2976             : 
    2977             : // Async Iteration proposal 11.4.3.6.
    2978             : MOZ_MUST_USE bool
    2979           0 : js::AsyncGeneratorEnqueue(JSContext* cx, HandleValue asyncGenVal,
    2980             :                           CompletionKind completionKind, HandleValue completionValue,
    2981             :                           MutableHandleValue result)
    2982             : {
    2983             :     // Step 1 (implicit).
    2984             : 
    2985             :     // Step 2.
    2986           0 :     RootedObject resultPromise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
    2987           0 :     if (!resultPromise)
    2988             :         return false;
    2989             : 
    2990             :     // Step 3.
    2991           0 :     if (!asyncGenVal.isObject() || !asyncGenVal.toObject().is<AsyncGeneratorObject>()) {
    2992             :         // Step 3.a.
    2993           0 :         RootedValue badGeneratorError(cx);
    2994           0 :         if (!GetTypeError(cx, JSMSG_NOT_AN_ASYNC_GENERATOR, &badGeneratorError))
    2995             :             return false;
    2996             : 
    2997             :         // Step 3.b.
    2998           0 :         if (!RejectMaybeWrappedPromise(cx, resultPromise, badGeneratorError))
    2999             :             return false;
    3000             : 
    3001             :         // Step 3.c.
    3002           0 :         result.setObject(*resultPromise);
    3003           0 :         return true;
    3004             :     }
    3005             : 
    3006             :     Rooted<AsyncGeneratorObject*> asyncGenObj(
    3007           0 :         cx, &asyncGenVal.toObject().as<AsyncGeneratorObject>());
    3008             : 
    3009             :     // Step 5 (reordered).
    3010             :     Rooted<AsyncGeneratorRequest*> request(
    3011           0 :         cx, AsyncGeneratorObject::createRequest(cx, asyncGenObj, completionKind, completionValue,
    3012           0 :                                                 resultPromise));
    3013           0 :     if (!request)
    3014             :         return false;
    3015             : 
    3016             :     // Steps 4, 6.
    3017           0 :     if (!AsyncGeneratorObject::enqueueRequest(cx, asyncGenObj, request))
    3018             :         return false;
    3019             : 
    3020             :     // Step 7.
    3021           0 :     if (!asyncGenObj->isExecuting()) {
    3022             :         // Step 8.
    3023           0 :         if (!AsyncGeneratorResumeNext(cx, asyncGenObj, ResumeNextKind::Enqueue))
    3024             :             return false;
    3025             :     }
    3026             : 
    3027             :     // Step 9.
    3028           0 :     result.setObject(*resultPromise);
    3029           0 :     return true;
    3030             : }
    3031             : 
    3032             : static bool Promise_then(JSContext* cx, unsigned argc, Value* vp);
    3033             : static bool Promise_then_impl(JSContext* cx, HandleValue promiseVal, HandleValue onFulfilled,
    3034             :                               HandleValue onRejected, MutableHandleValue rval, bool rvalUsed);
    3035             : 
    3036             : static bool
    3037         198 : Promise_catch_impl(JSContext* cx, unsigned argc, Value* vp, bool rvalUsed)
    3038             : {
    3039         198 :     CallArgs args = CallArgsFromVp(argc, vp);
    3040             : 
    3041             :     // Step 1.
    3042           0 :     RootedValue thenVal(cx);
    3043         792 :     if (!GetProperty(cx, args.thisv(), cx->names().then, &thenVal))
    3044             :         return false;
    3045             : 
    3046           0 :     if (IsNativeFunction(thenVal, &Promise_then)) {
    3047           0 :         return Promise_then_impl(cx, args.thisv(), UndefinedHandleValue, args.get(0),
    3048         198 :                                  args.rval(), rvalUsed);
    3049             :     }
    3050             : 
    3051           0 :     FixedInvokeArgs<2> iargs(cx);
    3052           0 :     iargs[0].setUndefined();
    3053           0 :     iargs[1].set(args.get(0));
    3054             : 
    3055           0 :     return Call(cx, thenVal, args.thisv(), iargs, args.rval());
    3056             : }
    3057             : 
    3058             : static MOZ_ALWAYS_INLINE bool
    3059         132 : IsPromiseThenOrCatchRetValImplicitlyUsed(JSContext* cx)
    3060             : {
    3061             :     // The returned promise of Promise#then and Promise#catch contains
    3062             :     // stack info if async stack is enabled.  Even if their return value is not
    3063             :     // used explicitly in the script, the stack info is observable in devtools
    3064             :     // and profilers.  We shouldn't apply the optimization not to allocate the
    3065             :     // returned Promise object if the it's implicitly used by them.
    3066             :     //
    3067             :     // FIXME: Once bug 1280819 gets fixed, we can use ShouldCaptureDebugInfo.
    3068         264 :     if (!cx->options().asyncStack())
    3069             :         return false;
    3070             : 
    3071             :     // If devtools is opened, the current realm will become debuggee.
    3072         264 :     if (cx->realm()->isDebuggee())
    3073             :         return true;
    3074             : 
    3075             :     // There are 2 profilers, and they can be independently enabled.
    3076         264 :     if (cx->runtime()->geckoProfiler().enabled())
    3077             :         return true;
    3078         132 :     if (JS::IsProfileTimelineRecordingEnabled())
    3079             :         return true;
    3080             : 
    3081             :     // The stack is also observable from Error#stack, but we don't care since
    3082             :     // it's nonstandard feature.
    3083         132 :     return false;
    3084             : }
    3085             : 
    3086             : // ES2016, 25.4.5.3.
    3087             : static bool
    3088          11 : Promise_catch_noRetVal(JSContext* cx, unsigned argc, Value* vp)
    3089             : {
    3090          11 :     return Promise_catch_impl(cx, argc, vp, IsPromiseThenOrCatchRetValImplicitlyUsed(cx));
    3091             : }
    3092             : 
    3093             : // ES2016, 25.4.5.3.
    3094             : static bool
    3095         187 : Promise_catch(JSContext* cx, unsigned argc, Value* vp)
    3096             : {
    3097         187 :     return Promise_catch_impl(cx, argc, vp, true);
    3098             : }
    3099             : 
    3100             : static bool
    3101        1833 : Promise_then_impl(JSContext* cx, HandleValue promiseVal, HandleValue onFulfilled,
    3102             :                   HandleValue onRejected, MutableHandleValue rval, bool rvalUsed)
    3103             : {
    3104             :     // Step 1 (implicit).
    3105             :     // Step 2.
    3106        1833 :     if (!promiseVal.isObject()) {
    3107             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
    3108           0 :                                   "Receiver of Promise.prototype.then call");
    3109           0 :         return false;
    3110             :     }
    3111           0 :     RootedObject promiseObj(cx, &promiseVal.toObject());
    3112        3666 :     Rooted<PromiseObject*> promise(cx);
    3113             : 
    3114           0 :     bool isPromise = promiseObj->is<PromiseObject>();
    3115           0 :     if (isPromise) {
    3116        3658 :         promise = &promiseObj->as<PromiseObject>();
    3117             :     } else {
    3118           0 :         RootedObject unwrappedPromiseObj(cx, CheckedUnwrap(promiseObj));
    3119           1 :         if (!unwrappedPromiseObj) {
    3120           0 :             ReportAccessDenied(cx);
    3121           0 :             return false;
    3122             :         }
    3123           8 :         if (!unwrappedPromiseObj->is<PromiseObject>()) {
    3124             :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
    3125           0 :                                       "Promise", "then", "value");
    3126           0 :             return false;
    3127             :         }
    3128           8 :         promise = &unwrappedPromiseObj->as<PromiseObject>();
    3129             :     }
    3130             : 
    3131             :     // Steps 3-5.
    3132             :     CreateDependentPromise createDependent = rvalUsed
    3133           0 :                                              ? CreateDependentPromise::Always
    3134           0 :                                              : CreateDependentPromise::SkipIfCtorUnobservable;
    3135           0 :     RootedObject resultPromise(cx);
    3136        3666 :     if (!OriginalPromiseThen(cx, promise, onFulfilled, onRejected, &resultPromise,
    3137             :                              createDependent))
    3138             :     {
    3139             :         return false;
    3140             :     }
    3141             : 
    3142           0 :     if (rvalUsed)
    3143        1701 :         rval.setObject(*resultPromise);
    3144             :     else
    3145             :         rval.setUndefined();
    3146             :     return true;
    3147             : }
    3148             : 
    3149             : // ES2016, 25.4.5.3.
    3150             : bool
    3151         121 : Promise_then_noRetVal(JSContext* cx, unsigned argc, Value* vp)
    3152             : {
    3153           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    3154           0 :     return Promise_then_impl(cx, args.thisv(), args.get(0), args.get(1), args.rval(),
    3155         242 :                              IsPromiseThenOrCatchRetValImplicitlyUsed(cx));
    3156             : }
    3157             : 
    3158             : // ES2016, 25.4.5.3.
    3159             : static bool
    3160        1514 : Promise_then(JSContext* cx, unsigned argc, Value* vp)
    3161             : {
    3162           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    3163        6056 :     return Promise_then_impl(cx, args.thisv(), args.get(0), args.get(1), args.rval(), true);
    3164             : }
    3165             : 
    3166             : // ES2016, 25.4.5.3.1.
    3167             : static MOZ_MUST_USE bool
    3168        2076 : PerformPromiseThen(JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled_,
    3169             :                    HandleValue onRejected_, HandleObject resultPromise,
    3170             :                    HandleObject resolve, HandleObject reject)
    3171             : {
    3172             :     // Step 1 (implicit).
    3173             :     // Step 2 (implicit).
    3174             : 
    3175             :     // Step 3.
    3176           0 :     RootedValue onFulfilled(cx, onFulfilled_);
    3177           0 :     if (!IsCallable(onFulfilled))
    3178         532 :         onFulfilled = Int32Value(PromiseHandlerIdentity);
    3179             : 
    3180             :     // Step 4.
    3181           0 :     RootedValue onRejected(cx, onRejected_);
    3182           0 :     if (!IsCallable(onRejected))
    3183         608 :         onRejected = Int32Value(PromiseHandlerThrower);
    3184             : 
    3185           0 :     RootedObject incumbentGlobal(cx);
    3186        2076 :     if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal))
    3187             :         return false;
    3188             : 
    3189             :     // Step 7.
    3190        8304 :     Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise,
    3191             :                                                                   onFulfilled, onRejected,
    3192             :                                                                   resolve, reject,
    3193           0 :                                                                   incumbentGlobal));
    3194        2076 :     if (!reaction)
    3195             :         return false;
    3196             : 
    3197        2076 :     return PerformPromiseThenWithReaction(cx, promise, reaction);
    3198             : }
    3199             : 
    3200             : static MOZ_MUST_USE bool
    3201        3143 : PerformPromiseThenWithReaction(JSContext* cx, Handle<PromiseObject*> promise,
    3202             :                                Handle<PromiseReactionRecord*> reaction)
    3203             : {
    3204           0 :     JS::PromiseState state = promise->state();
    3205           0 :     int32_t flags = promise->getFixedSlot(PromiseSlot_Flags).toInt32();
    3206        3143 :     if (state == JS::PromiseState::Pending) {
    3207             :         // Steps 5,6 (reordered).
    3208             :         // Instead of creating separate reaction records for fulfillment and
    3209             :         // rejection, we create a combined record. All places we use the record
    3210             :         // can handle that.
    3211        2631 :         if (!AddPromiseReaction(cx, promise, reaction))
    3212             :             return false;
    3213             :     }
    3214             : 
    3215             :     // Steps 8,9.
    3216             :     else {
    3217             :         // Step 9.a.
    3218         512 :         MOZ_ASSERT_IF(state != JS::PromiseState::Fulfilled, state == JS::PromiseState::Rejected);
    3219             : 
    3220             :         // Step 8.a. / 9.b.
    3221        1024 :         RootedValue valueOrReason(cx, promise->getFixedSlot(PromiseSlot_ReactionsOrResult));
    3222             : 
    3223             :         // We might be operating on a promise from another compartment. In
    3224             :         // that case, we need to wrap the result/reason value before using it.
    3225           1 :         if (!cx->compartment()->wrap(cx, &valueOrReason))
    3226           0 :             return false;
    3227             : 
    3228             :         // Step 9.c.
    3229           0 :         if (state == JS::PromiseState::Rejected && !(flags & PROMISE_FLAG_HANDLED))
    3230           2 :             cx->runtime()->removeUnhandledRejectedPromise(cx, promise);
    3231             : 
    3232             :         // Step 8.b. / 9.d.
    3233        1024 :         if (!EnqueuePromiseReactionJob(cx, reaction, valueOrReason, state))
    3234             :             return false;
    3235             :     }
    3236             : 
    3237             :     // Step 10.
    3238        9429 :     promise->setFixedSlot(PromiseSlot_Flags, Int32Value(flags | PROMISE_FLAG_HANDLED));
    3239             : 
    3240             :     // Step 11.
    3241        3143 :     return true;
    3242             : }
    3243             : 
    3244             : /**
    3245             :  * Calls |promise.then| with the provided hooks and adds |blockedPromise| to
    3246             :  * its list of dependent promises. Used by |Promise.all| and |Promise.race|.
    3247             :  *
    3248             :  * If |promise.then| is the original |Promise.prototype.then| function and
    3249             :  * the call to |promise.then| would use the original |Promise| constructor to
    3250             :  * create the resulting promise, this function skips the call to |promise.then|
    3251             :  * and thus creating a new promise that would not be observable by content.
    3252             :  */
    3253             : static MOZ_MUST_USE bool
    3254         242 : BlockOnPromise(JSContext* cx, HandleValue promiseVal, HandleObject blockedPromise_,
    3255             :                HandleValue onFulfilled, HandleValue onRejected)
    3256             : {
    3257           0 :     RootedObject promiseObj(cx, ToObject(cx, promiseVal));
    3258         242 :     if (!promiseObj)
    3259             :         return false;
    3260             : 
    3261           0 :     RootedValue thenVal(cx);
    3262         968 :     if (!GetProperty(cx, promiseObj, promiseVal, cx->names().then, &thenVal))
    3263             :         return false;
    3264             : 
    3265         726 :     if (promiseObj->is<PromiseObject>() && IsNativeFunction(thenVal, Promise_then)) {
    3266             :         // |promise| is an unwrapped Promise, and |then| is the original
    3267             :         // |Promise.prototype.then|, inline it here.
    3268             :         // 25.4.5.3., step 3.
    3269             :         RootedObject PromiseCtor(cx,
    3270           0 :                                  GlobalObject::getOrCreatePromiseConstructor(cx, cx->global()));
    3271           0 :         if (!PromiseCtor)
    3272         242 :             return false;
    3273             : 
    3274           0 :         RootedObject C(cx, SpeciesConstructor(cx, promiseObj, JSProto_Promise, IsPromiseSpecies));
    3275           0 :         if (!C)
    3276         242 :             return false;
    3277             : 
    3278           0 :         RootedObject resultPromise(cx, blockedPromise_);
    3279           0 :         RootedObject resolveFun(cx);
    3280         242 :         RootedObject rejectFun(cx);
    3281             : 
    3282             :         // By default, the blocked promise is added as an extra entry to the
    3283             :         // rejected promises list.
    3284         242 :         bool addToDependent = true;
    3285             : 
    3286         726 :         if (C == PromiseCtor && resultPromise->is<PromiseObject>()) {
    3287             :             addToDependent = false;
    3288             :         } else {
    3289             :             // 25.4.5.3., step 4.
    3290           0 :             if (!NewPromiseCapability(cx, C, &resultPromise, &resolveFun, &rejectFun, true))
    3291         242 :                 return false;
    3292             :         }
    3293             : 
    3294             :         // 25.4.5.3., step 5.
    3295           0 :         Rooted<PromiseObject*> promise(cx, &promiseObj->as<PromiseObject>());
    3296         968 :         if (!PerformPromiseThen(cx, promise, onFulfilled, onRejected, resultPromise,
    3297             :                                 resolveFun, rejectFun))
    3298             :         {
    3299         242 :             return false;
    3300             :         }
    3301             : 
    3302         242 :         if (!addToDependent)
    3303             :             return true;
    3304             :     } else {
    3305             :         // Optimization failed, do the normal call.
    3306           0 :         RootedValue rval(cx);
    3307           0 :         if (!Call(cx, thenVal, promiseVal, onFulfilled, onRejected, &rval))
    3308           0 :             return false;
    3309             :     }
    3310             : 
    3311             :     // In case the value to depend on isn't an object at all, there's nothing
    3312             :     // more to do here: we can only add reactions to Promise objects
    3313             :     // (potentially after unwrapping them), and non-object values can't be
    3314             :     // Promise objects. This can happen if Promise.all is called on an object
    3315             :     // with a `resolve` method that returns primitives.
    3316           0 :     if (!promiseVal.isObject())
    3317             :         return true;
    3318             : 
    3319             :     // The object created by the |promise.then| call or the inlined version
    3320             :     // of it above is visible to content (either because |promise.then| was
    3321             :     // overridden by content and could leak it, or because a constructor
    3322             :     // other than the original value of |Promise| was used to create it).
    3323             :     // To have both that object and |blockedPromise| show up as dependent
    3324             :     // promises in the debugger, add a dummy reaction to the list of reject
    3325             :     // reactions that contains |blockedPromise|, but otherwise does nothing.
    3326           0 :     RootedObject unwrappedPromiseObj(cx, promiseObj);
    3327           0 :     RootedObject blockedPromise(cx, blockedPromise_);
    3328             : 
    3329           0 :     mozilla::Maybe<AutoRealm> ar;
    3330           0 :     if (IsProxy(promiseObj)) {
    3331           0 :         unwrappedPromiseObj = CheckedUnwrap(promiseObj);
    3332           0 :         if (!unwrappedPromiseObj) {
    3333           0 :             ReportAccessDenied(cx);
    3334           0 :             return false;
    3335             :         }
    3336           0 :         if (JS_IsDeadWrapper(unwrappedPromiseObj)) {
    3337           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
    3338           0 :             return false;
    3339             :         }
    3340           0 :         ar.emplace(cx, unwrappedPromiseObj);
    3341           0 :         if (!cx->compartment()->wrap(cx, &blockedPromise))
    3342             :             return false;
    3343             :     }
    3344             : 
    3345             :     // If either the object to depend on or the object that gets blocked isn't
    3346             :     // a, maybe-wrapped, Promise instance, we ignore it. All this does is lose
    3347             :     // some small amount of debug information in scenarios that are highly
    3348             :     // unlikely to occur in useful code.
    3349           0 :     if (!unwrappedPromiseObj->is<PromiseObject>())
    3350             :         return true;
    3351           0 :     if (!blockedPromise_->is<PromiseObject>())
    3352             :         return true;
    3353             : 
    3354           0 :     Rooted<PromiseObject*> promise(cx, &unwrappedPromiseObj->as<PromiseObject>());
    3355           0 :     return AddPromiseReaction(cx, promise, UndefinedHandleValue, UndefinedHandleValue,
    3356           0 :                               blockedPromise, nullptr, nullptr, nullptr);
    3357             : }
    3358             : 
    3359             : static MOZ_MUST_USE bool
    3360        2631 : AddPromiseReaction(JSContext* cx, Handle<PromiseObject*> promise,
    3361             :                    Handle<PromiseReactionRecord*> reaction)
    3362             : {
    3363           0 :     MOZ_RELEASE_ASSERT(reaction->is<PromiseReactionRecord>());
    3364        7893 :     RootedValue reactionVal(cx, ObjectValue(*reaction));
    3365             : 
    3366             :     // The code that creates Promise reactions can handle wrapped Promises,
    3367             :     // unwrapping them as needed. That means that the `promise` and `reaction`
    3368             :     // objects we have here aren't necessarily from the same compartment. In
    3369             :     // order to store the reaction on the promise, we have to ensure that it
    3370             :     // is properly wrapped.
    3371           0 :     mozilla::Maybe<AutoRealm> ar;
    3372           0 :     if (promise->compartment() != cx->compartment()) {
    3373           0 :         ar.emplace(cx, promise);
    3374           6 :         if (!cx->compartment()->wrap(cx, &reactionVal))
    3375             :             return false;
    3376             :     }
    3377             : 
    3378             :     // 25.4.5.3.1 steps 7.a,b.
    3379           0 :     RootedValue reactionsVal(cx, promise->getFixedSlot(PromiseSlot_ReactionsOrResult));
    3380        5262 :     RootedNativeObject reactions(cx);
    3381             : 
    3382        2631 :     if (reactionsVal.isUndefined()) {
    3383             :         // If no reactions existed so far, just store the reaction record directly.
    3384           0 :         promise->setFixedSlot(PromiseSlot_ReactionsOrResult, reactionVal);
    3385        2494 :         return true;
    3386             :     }
    3387             : 
    3388         274 :     RootedObject reactionsObj(cx, &reactionsVal.toObject());
    3389             : 
    3390             :     // If only a single reaction exists, it's stored directly instead of in a
    3391             :     // list. In that case, `reactionsObj` might be a wrapper, which we can
    3392             :     // always safely unwrap.
    3393           0 :     if (IsProxy(reactionsObj)) {
    3394           0 :         reactionsObj = UncheckedUnwrap(reactionsObj);
    3395           0 :         if (JS_IsDeadWrapper(reactionsObj)) {
    3396           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
    3397           0 :             return false;
    3398             :         }
    3399           0 :         MOZ_RELEASE_ASSERT(reactionsObj->is<PromiseReactionRecord>());
    3400             :     }
    3401             : 
    3402         274 :     if (reactionsObj->is<PromiseReactionRecord>()) {
    3403             :         // If a single reaction existed so far, create a list and store the
    3404             :         // old and the new reaction in it.
    3405           0 :         reactions = NewDenseFullyAllocatedArray(cx, 2);
    3406         134 :         if (!reactions)
    3407             :             return false;
    3408         268 :         if (reactions->ensureDenseElements(cx, 0, 2) != DenseElementResult::Success)
    3409             :             return false;
    3410             : 
    3411           0 :         reactions->setDenseElement(0, reactionsVal);
    3412         268 :         reactions->setDenseElement(1, reactionVal);
    3413             : 
    3414         402 :         promise->setFixedSlot(PromiseSlot_ReactionsOrResult, ObjectValue(*reactions));
    3415             :     } else {
    3416             :         // Otherwise, just store the new reaction.
    3417           0 :         MOZ_RELEASE_ASSERT(reactionsObj->is<NativeObject>());
    3418           0 :         reactions = &reactionsObj->as<NativeObject>();
    3419           0 :         uint32_t len = reactions->getDenseInitializedLength();
    3420           6 :         if (reactions->ensureDenseElements(cx, 0, len + 1) != DenseElementResult::Success)
    3421             :             return false;
    3422           6 :         reactions->setDenseElement(len, reactionVal);
    3423             :     }
    3424             : 
    3425             :     return true;
    3426             : }
    3427             : 
    3428             : static MOZ_MUST_USE bool
    3429           0 : AddPromiseReaction(JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled,
    3430             :                    HandleValue onRejected, HandleObject dependentPromise,
    3431             :                    HandleObject resolve, HandleObject reject, HandleObject incumbentGlobal)
    3432             : {
    3433           0 :     if (promise->state() != JS::PromiseState::Pending)
    3434             :         return true;
    3435             : 
    3436           0 :     Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, dependentPromise,
    3437             :                                                                   onFulfilled, onRejected,
    3438             :                                                                   resolve, reject,
    3439           0 :                                                                   incumbentGlobal));
    3440           0 :     if (!reaction)
    3441             :         return false;
    3442           0 :     return AddPromiseReaction(cx, promise, reaction);
    3443             : }
    3444             : 
    3445             : uint64_t
    3446           0 : PromiseObject::getID()
    3447             : {
    3448           0 :     return PromiseDebugInfo::id(this);
    3449             : }
    3450             : 
    3451             : double
    3452           0 : PromiseObject::lifetime()
    3453             : {
    3454           0 :     return MillisecondsSinceStartup() - allocationTime();
    3455             : }
    3456             : 
    3457             : /**
    3458             :  * Returns all promises that directly depend on this one. That means those
    3459             :  * created by calling `then` on this promise, or the promise returned by
    3460             :  * `Promise.all(iterable)` or `Promise.race(iterable)`, with this promise
    3461             :  * being a member of the passed-in `iterable`.
    3462             :  *
    3463             :  * Per spec, we should have separate lists of reaction records for the
    3464             :  * fulfill and reject cases. As an optimization, we have only one of those,
    3465             :  * containing the required data for both cases. So we just walk that list
    3466             :  * and extract the dependent promises from all reaction records.
    3467             :  */
    3468             : bool
    3469           0 : PromiseObject::dependentPromises(JSContext* cx, MutableHandle<GCVector<Value>> values)
    3470             : {
    3471           0 :     if (state() != JS::PromiseState::Pending)
    3472             :         return true;
    3473             : 
    3474           0 :     RootedValue reactionsVal(cx, getFixedSlot(PromiseSlot_ReactionsOrResult));
    3475             : 
    3476             :     // If no reactions are pending, we don't have list and are done.
    3477           0 :     if (reactionsVal.isNullOrUndefined())
    3478             :         return true;
    3479             : 
    3480           0 :     RootedNativeObject reactions(cx, &reactionsVal.toObject().as<NativeObject>());
    3481             : 
    3482             :     // If only a single reaction is pending, it's stored directly.
    3483           0 :     if (reactions->is<PromiseReactionRecord>()) {
    3484             :         // Not all reactions have a Promise on them.
    3485           0 :         RootedObject promiseObj(cx, reactions->as<PromiseReactionRecord>().promise());
    3486           0 :         if (!promiseObj)
    3487             :             return true;
    3488             : 
    3489           0 :         if (!values.growBy(1))
    3490             :             return false;
    3491             : 
    3492           0 :         values[0].setObject(*promiseObj);
    3493           0 :         return true;
    3494             :     }
    3495             : 
    3496           0 :     uint32_t len = reactions->getDenseInitializedLength();
    3497           0 :     MOZ_ASSERT(len >= 2);
    3498             : 
    3499           0 :     size_t valuesIndex = 0;
    3500           0 :     Rooted<PromiseReactionRecord*> reaction(cx);
    3501           0 :     for (size_t i = 0; i < len; i++) {
    3502           0 :         reaction = &reactions->getDenseElement(i).toObject().as<PromiseReactionRecord>();
    3503             : 
    3504             :         // Not all reactions have a Promise on them.
    3505           0 :         RootedObject promiseObj(cx, reaction->promise());
    3506           0 :         if (!promiseObj)
    3507           0 :             continue;
    3508           0 :         if (!values.growBy(1))
    3509           0 :             return false;
    3510             : 
    3511           0 :         values[valuesIndex++].setObject(*promiseObj);
    3512             :     }
    3513             : 
    3514             :     return true;
    3515             : }
    3516             : 
    3517             : /* static */ bool
    3518         117 : PromiseObject::resolve(JSContext* cx, Handle<PromiseObject*> promise, HandleValue resolutionValue)
    3519             : {
    3520           0 :     MOZ_ASSERT(!PromiseHasAnyFlag(*promise, PROMISE_FLAG_ASYNC));
    3521         117 :     if (promise->state() != JS::PromiseState::Pending)
    3522             :         return true;
    3523             : 
    3524           0 :     if (PromiseHasAnyFlag(*promise, PROMISE_FLAG_DEFAULT_RESOLVE_FUNCTION))
    3525          97 :         return ResolvePromiseInternal(cx, promise, resolutionValue);
    3526             : 
    3527           0 :     RootedObject resolveFun(cx, GetResolveFunctionFromPromise(promise));
    3528           0 :     RootedValue funVal(cx, ObjectValue(*resolveFun));
    3529             : 
    3530             :     // For xray'd Promises, the resolve fun may have been created in another
    3531             :     // compartment. For the call below to work in that case, wrap the
    3532             :     // function into the current compartment.
    3533           0 :     if (!cx->compartment()->wrap(cx, &funVal))
    3534             :         return false;
    3535             : 
    3536           0 :     FixedInvokeArgs<1> args(cx);
    3537           0 :     args[0].set(resolutionValue);
    3538             : 
    3539           0 :     RootedValue dummy(cx);
    3540           0 :     return Call(cx, funVal, UndefinedHandleValue, args, &dummy);
    3541             : }
    3542             : 
    3543             : /* static */ bool
    3544           0 : PromiseObject::reject(JSContext* cx, Handle<PromiseObject*> promise, HandleValue rejectionValue)
    3545             : {
    3546           0 :     MOZ_ASSERT(!PromiseHasAnyFlag(*promise, PROMISE_FLAG_ASYNC));
    3547           0 :     if (promise->state() != JS::PromiseState::Pending)
    3548             :         return true;
    3549             : 
    3550           0 :     if (PromiseHasAnyFlag(*promise, PROMISE_FLAG_DEFAULT_REJECT_FUNCTION))
    3551           0 :         return ResolvePromise(cx, promise, rejectionValue, JS::PromiseState::Rejected);
    3552             : 
    3553           0 :     RootedValue funVal(cx, promise->getFixedSlot(PromiseSlot_RejectFunction));
    3554           0 :     MOZ_ASSERT(IsCallable(funVal));
    3555             : 
    3556           0 :     FixedInvokeArgs<1> args(cx);
    3557           0 :     args[0].set(rejectionValue);
    3558             : 
    3559           0 :     RootedValue dummy(cx);
    3560           0 :     return Call(cx, funVal, UndefinedHandleValue, args, &dummy);
    3561             : }
    3562             : 
    3563             : /* static */ void
    3564        4103 : PromiseObject::onSettled(JSContext* cx, Handle<PromiseObject*> promise)
    3565             : {
    3566        4103 :     PromiseDebugInfo::setResolutionInfo(cx, promise);
    3567             : 
    3568           0 :     if (promise->state() == JS::PromiseState::Rejected && promise->isUnhandled())
    3569           4 :         cx->runtime()->addUnhandledRejectedPromise(cx, promise);
    3570             : 
    3571           0 :     Debugger::onPromiseSettled(cx, promise);
    3572        4103 : }
    3573             : 
    3574           0 : OffThreadPromiseTask::OffThreadPromiseTask(JSContext* cx, Handle<PromiseObject*> promise)
    3575           0 :   : runtime_(cx->runtime()),
    3576             :     promise_(cx, promise),
    3577           0 :     registered_(false)
    3578             : {
    3579           0 :     MOZ_ASSERT(runtime_ == promise_->zone()->runtimeFromMainThread());
    3580           0 :     MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
    3581           0 :     MOZ_ASSERT(cx->runtime()->offThreadPromiseState.ref().initialized());
    3582           0 : }
    3583             : 
    3584           0 : OffThreadPromiseTask::~OffThreadPromiseTask()
    3585             : {
    3586           0 :     MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
    3587             : 
    3588           0 :     OffThreadPromiseRuntimeState& state = runtime_->offThreadPromiseState.ref();
    3589           0 :     MOZ_ASSERT(state.initialized());
    3590             : 
    3591           0 :     if (registered_) {
    3592           0 :         LockGuard<Mutex> lock(state.mutex_);
    3593           0 :         state.live_.remove(this);
    3594             :     }
    3595           0 : }
    3596             : 
    3597             : bool
    3598           0 : OffThreadPromiseTask::init(JSContext* cx)
    3599             : {
    3600           0 :     MOZ_ASSERT(cx->runtime() == runtime_);
    3601           0 :     MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
    3602             : 
    3603           0 :     OffThreadPromiseRuntimeState& state = runtime_->offThreadPromiseState.ref();
    3604           0 :     MOZ_ASSERT(state.initialized());
    3605             : 
    3606           0 :     LockGuard<Mutex> lock(state.mutex_);
    3607             : 
    3608           0 :     if (!state.live_.putNew(this)) {
    3609           0 :         ReportOutOfMemory(cx);
    3610           0 :         return false;
    3611             :     }
    3612             : 
    3613           0 :     registered_ = true;
    3614           0 :     return true;
    3615             : }
    3616             : 
    3617             : void
    3618           0 : OffThreadPromiseTask::run(JSContext* cx, MaybeShuttingDown maybeShuttingDown)
    3619             : {
    3620           0 :     MOZ_ASSERT(cx->runtime() == runtime_);
    3621           0 :     MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
    3622           0 :     MOZ_ASSERT(registered_);
    3623           0 :     MOZ_ASSERT(runtime_->offThreadPromiseState.ref().initialized());
    3624             : 
    3625           0 :     if (maybeShuttingDown == JS::Dispatchable::NotShuttingDown) {
    3626             :         // We can't leave a pending exception when returning to the caller so do
    3627             :         // the same thing as Gecko, which is to ignore the error. This should
    3628             :         // only happen due to OOM or interruption.
    3629           0 :         AutoRealm ar(cx, promise_);
    3630           0 :         if (!resolve(cx, promise_))
    3631           0 :             cx->clearPendingException();
    3632             :     }
    3633             : 
    3634           0 :     js_delete(this);
    3635           0 : }
    3636             : 
    3637             : void
    3638           0 : OffThreadPromiseTask::dispatchResolveAndDestroy()
    3639             : {
    3640           0 :     MOZ_ASSERT(registered_);
    3641             : 
    3642           0 :     OffThreadPromiseRuntimeState& state = runtime_->offThreadPromiseState.ref();
    3643           0 :     MOZ_ASSERT(state.initialized());
    3644           0 :     MOZ_ASSERT((LockGuard<Mutex>(state.mutex_), state.live_.has(this)));
    3645             : 
    3646             :     // If the dispatch succeeds, then we are guaranteed that run() will be
    3647             :     // called on an active JSContext of runtime_.
    3648           0 :     if (state.dispatchToEventLoopCallback_(state.dispatchToEventLoopClosure_, this))
    3649             :         return;
    3650             : 
    3651             :     // We assume, by interface contract, that if the dispatch fails, it's
    3652             :     // because the embedding is in the process of shutting down the JSRuntime.
    3653             :     // Since JSRuntime destruction calls shutdown(), we can rely on shutdown()
    3654             :     // to delete the task on its active JSContext thread. shutdown() waits for
    3655             :     // numCanceled_ == live_.length, so we notify when this condition is
    3656             :     // reached.
    3657           0 :     LockGuard<Mutex> lock(state.mutex_);
    3658           0 :     state.numCanceled_++;
    3659           0 :     if (state.numCanceled_ == state.live_.count())
    3660           0 :         state.allCanceled_.notify_one();
    3661             : }
    3662             : 
    3663           4 : OffThreadPromiseRuntimeState::OffThreadPromiseRuntimeState()
    3664             :   : dispatchToEventLoopCallback_(nullptr),
    3665             :     dispatchToEventLoopClosure_(nullptr),
    3666             :     mutex_(mutexid::OffThreadPromiseState),
    3667             :     numCanceled_(0),
    3668          20 :     internalDispatchQueueClosed_(false)
    3669             : {
    3670           0 :     AutoEnterOOMUnsafeRegion noOOM;
    3671           1 :     if (!live_.init())
    3672           0 :         noOOM.crash("OffThreadPromiseRuntimeState");
    3673           4 : }
    3674             : 
    3675           0 : OffThreadPromiseRuntimeState::~OffThreadPromiseRuntimeState()
    3676             : {
    3677           0 :     MOZ_ASSERT(live_.empty());
    3678           0 :     MOZ_ASSERT(numCanceled_ == 0);
    3679           0 :     MOZ_ASSERT(internalDispatchQueue_.empty());
    3680           0 :     MOZ_ASSERT(!initialized());
    3681           0 : }
    3682             : 
    3683             : void
    3684           4 : OffThreadPromiseRuntimeState::init(JS::DispatchToEventLoopCallback callback, void* closure)
    3685             : {
    3686           4 :     MOZ_ASSERT(!initialized());
    3687             : 
    3688           0 :     dispatchToEventLoopCallback_ = callback;
    3689           4 :     dispatchToEventLoopClosure_ = closure;
    3690             : 
    3691           0 :     MOZ_ASSERT(initialized());
    3692           4 : }
    3693             : 
    3694             : /* static */ bool
    3695           0 : OffThreadPromiseRuntimeState::internalDispatchToEventLoop(void* closure, JS::Dispatchable* d)
    3696             : {
    3697           0 :     OffThreadPromiseRuntimeState& state = *reinterpret_cast<OffThreadPromiseRuntimeState*>(closure);
    3698           0 :     MOZ_ASSERT(state.usingInternalDispatchQueue());
    3699             : 
    3700           0 :     LockGuard<Mutex> lock(state.mutex_);
    3701             : 
    3702           0 :     if (state.internalDispatchQueueClosed_)
    3703             :         return false;
    3704             : 
    3705             :     // The JS API contract is that 'false' means shutdown, so be infallible
    3706             :     // here (like Gecko).
    3707           0 :     AutoEnterOOMUnsafeRegion noOOM;
    3708           0 :     if (!state.internalDispatchQueue_.append(d))
    3709           0 :         noOOM.crash("internalDispatchToEventLoop");
    3710             : 
    3711             :     // Wake up internalDrain() if it is waiting for a job to finish.
    3712           0 :     state.internalDispatchQueueAppended_.notify_one();
    3713             :     return true;
    3714             : }
    3715             : 
    3716             : bool
    3717           0 : OffThreadPromiseRuntimeState::usingInternalDispatchQueue() const
    3718             : {
    3719           0 :     return dispatchToEventLoopCallback_ == internalDispatchToEventLoop;
    3720             : }
    3721             : 
    3722             : void
    3723           0 : OffThreadPromiseRuntimeState::initInternalDispatchQueue()
    3724             : {
    3725           0 :     init(internalDispatchToEventLoop, this);
    3726           0 :     MOZ_ASSERT(usingInternalDispatchQueue());
    3727           0 : }
    3728             : 
    3729             : bool
    3730           0 : OffThreadPromiseRuntimeState::initialized() const
    3731             : {
    3732           4 :     return !!dispatchToEventLoopCallback_;
    3733             : }
    3734             : 
    3735             : void
    3736           0 : OffThreadPromiseRuntimeState::internalDrain(JSContext* cx)
    3737             : {
    3738           0 :     MOZ_ASSERT(usingInternalDispatchQueue());
    3739           0 :     MOZ_ASSERT(!internalDispatchQueueClosed_);
    3740             : 
    3741             :     while (true) {
    3742           0 :         DispatchableVector dispatchQueue;
    3743             :         {
    3744           0 :             LockGuard<Mutex> lock(mutex_);
    3745             : 
    3746           0 :             MOZ_ASSERT_IF(!internalDispatchQueue_.empty(), !live_.empty());
    3747           0 :             if (live_.empty())
    3748           0 :                 return;
    3749             : 
    3750           0 :             while (internalDispatchQueue_.empty())
    3751           0 :                 internalDispatchQueueAppended_.wait(lock);
    3752             : 
    3753           0 :             Swap(dispatchQueue, internalDispatchQueue_);
    3754           0 :             MOZ_ASSERT(internalDispatchQueue_.empty());
    3755             :         }
    3756             : 
    3757             :         // Don't call run() with mutex_ held to avoid deadlock.
    3758           0 :         for (JS::Dispatchable* d : dispatchQueue)
    3759           0 :             d->run(cx, JS::Dispatchable::NotShuttingDown);
    3760             :     }
    3761             : }
    3762             : 
    3763             : bool
    3764           0 : OffThreadPromiseRuntimeState::internalHasPending()
    3765             : {
    3766           0 :     MOZ_ASSERT(usingInternalDispatchQueue());
    3767           0 :     MOZ_ASSERT(!internalDispatchQueueClosed_);
    3768             : 
    3769           0 :     LockGuard<Mutex> lock(mutex_);
    3770           0 :     MOZ_ASSERT_IF(!internalDispatchQueue_.empty(), !live_.empty());
    3771           0 :     return !live_.empty();
    3772             : }
    3773             : 
    3774             : void
    3775           0 : OffThreadPromiseRuntimeState::shutdown(JSContext* cx)
    3776             : {
    3777           0 :     if (!initialized())
    3778             :         return;
    3779             : 
    3780             :     // When the shell is using the internal event loop, we must simulate our
    3781             :     // requirement of the embedding that, before shutdown, all successfully-
    3782             :     // dispatched-to-event-loop tasks have been run.
    3783           0 :     if (usingInternalDispatchQueue()) {
    3784           0 :         DispatchableVector dispatchQueue;
    3785             :         {
    3786           0 :             LockGuard<Mutex> lock(mutex_);
    3787           0 :             Swap(dispatchQueue, internalDispatchQueue_);
    3788           0 :             MOZ_ASSERT(internalDispatchQueue_.empty());
    3789           0 :             internalDispatchQueueClosed_ = true;
    3790             :         }
    3791             : 
    3792             :         // Don't call run() with mutex_ held to avoid deadlock.
    3793           0 :         for (JS::Dispatchable* d : dispatchQueue)
    3794           0 :             d->run(cx, JS::Dispatchable::ShuttingDown);
    3795             :     }
    3796             : 
    3797             :     {
    3798             :         // Wait until all live OffThreadPromiseRuntimeState have been confirmed
    3799             :         // canceled by OffThreadPromiseTask::dispatchResolve().
    3800           0 :         LockGuard<Mutex> lock(mutex_);
    3801           0 :         while (live_.count() != numCanceled_) {
    3802           0 :             MOZ_ASSERT(numCanceled_ < live_.count());
    3803           0 :             allCanceled_.wait(lock);
    3804             :         }
    3805             :     }
    3806             : 
    3807             :     // Now that all the tasks have stopped concurrent execution, we can just
    3808             :     // delete everything. We don't want each OffThreadPromiseTask to unregister
    3809             :     // itself (which would mutate live_ while we are iterating over it) so reset
    3810             :     // the tasks' internal registered_ flag.
    3811           0 :     for (OffThreadPromiseTaskSet::Range r = live_.all(); !r.empty(); r.popFront()) {
    3812           0 :         OffThreadPromiseTask* task = r.front();
    3813           0 :         MOZ_ASSERT(task->registered_);
    3814           0 :         task->registered_ = false;
    3815           0 :         js_delete(task);
    3816             :     }
    3817           0 :     live_.clear();
    3818           0 :     numCanceled_ = 0;
    3819             : 
    3820             :     // After shutdown, there should be no OffThreadPromiseTask activity in this
    3821             :     // JSRuntime. Revert to the !initialized() state to catch bugs.
    3822           0 :     dispatchToEventLoopCallback_ = nullptr;
    3823           0 :     MOZ_ASSERT(!initialized());
    3824             : }
    3825             : 
    3826             : static JSObject*
    3827          22 : CreatePromisePrototype(JSContext* cx, JSProtoKey key)
    3828             : {
    3829             :     return GlobalObject::createBlankPrototype(cx, cx->global(), &PromiseObject::protoClass_);
    3830             : }
    3831             : 
    3832             : const JSJitInfo promise_then_info = {
    3833             :   { (JSJitGetterOp)Promise_then_noRetVal },
    3834             :   { 0 }, /* unused */
    3835             :   { 0 }, /* unused */
    3836             :   JSJitInfo::IgnoresReturnValueNative,
    3837             :   JSJitInfo::AliasEverything,
    3838             :   JSVAL_TYPE_UNDEFINED,
    3839             : };
    3840             : 
    3841             : const JSJitInfo promise_catch_info = {
    3842             :   { (JSJitGetterOp)Promise_catch_noRetVal },
    3843             :   { 0 }, /* unused */
    3844             :   { 0 }, /* unused */
    3845             :   JSJitInfo::IgnoresReturnValueNative,
    3846             :   JSJitInfo::AliasEverything,
    3847             :   JSVAL_TYPE_UNDEFINED,
    3848             : };
    3849             : 
    3850             : static const JSFunctionSpec promise_methods[] = {
    3851             :     JS_FNINFO("then", Promise_then, &promise_then_info, 2, 0),
    3852             :     JS_FNINFO("catch", Promise_catch, &promise_catch_info, 1, 0),
    3853             :     JS_SELF_HOSTED_FN("finally", "Promise_finally", 1, 0),
    3854             :     JS_FS_END
    3855             : };
    3856             : 
    3857             : static const JSPropertySpec promise_properties[] = {
    3858             :     JS_STRING_SYM_PS(toStringTag, "Promise", JSPROP_READONLY),
    3859             :     JS_PS_END
    3860             : };
    3861             : 
    3862             : static const JSFunctionSpec promise_static_methods[] = {
    3863             :     JS_FN("all", Promise_static_all, 1, 0),
    3864             :     JS_FN("race", Promise_static_race, 1, 0),
    3865             :     JS_FN("reject", Promise_reject, 1, 0),
    3866             :     JS_FN("resolve", Promise_static_resolve, 1, 0),
    3867             :     JS_FS_END
    3868             : };
    3869             : 
    3870             : static const JSPropertySpec promise_static_properties[] = {
    3871             :     JS_SYM_GET(species, Promise_static_species, 0),
    3872             :     JS_PS_END
    3873             : };
    3874             : 
    3875             : static const ClassSpec PromiseObjectClassSpec = {
    3876             :     GenericCreateConstructor<PromiseConstructor, 1, gc::AllocKind::FUNCTION>,
    3877             :     CreatePromisePrototype,
    3878             :     promise_static_methods,
    3879             :     promise_static_properties,
    3880             :     promise_methods,
    3881             :     promise_properties
    3882             : };
    3883             : 
    3884             : const Class PromiseObject::class_ = {
    3885             :     "Promise",
    3886             :     JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_Promise) |
    3887             :     JSCLASS_HAS_XRAYED_CONSTRUCTOR,
    3888             :     JS_NULL_CLASS_OPS,
    3889             :     &PromiseObjectClassSpec
    3890             : };
    3891             : 
    3892             : const Class PromiseObject::protoClass_ = {
    3893             :     "PromiseProto",
    3894             :     JSCLASS_HAS_CACHED_PROTO(JSProto_Promise),
    3895             :     JS_NULL_CLASS_OPS,
    3896             :     &PromiseObjectClassSpec
    3897             : };

Generated by: LCOV version 1.13-14-ga5dd952