tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Promise.cpp (284206B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      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 #include "builtin/Promise.h"
      8 
      9 #include "mozilla/Atomics.h"
     10 #include "mozilla/Maybe.h"
     11 #include "mozilla/TimeStamp.h"
     12 
     13 #include "jsapi.h"
     14 #include "jsexn.h"
     15 #include "jsfriendapi.h"
     16 
     17 #include "js/CallAndConstruct.h"      // JS::Construct, JS::IsCallable
     18 #include "js/experimental/JitInfo.h"  // JSJitGetterOp, JSJitInfo
     19 #include "js/ForOfIterator.h"         // JS::ForOfIterator
     20 #include "js/friend/ErrorMessages.h"  // js::GetErrorMessage, JSMSG_*
     21 #include "js/PropertySpec.h"
     22 #include "js/Stack.h"
     23 #include "vm/ArrayObject.h"
     24 #include "vm/AsyncFunction.h"
     25 #include "vm/AsyncIteration.h"
     26 #include "vm/CompletionKind.h"
     27 #include "vm/ErrorObject.h"
     28 #include "vm/ErrorReporting.h"
     29 #include "vm/Iteration.h"
     30 #include "vm/JSContext.h"
     31 #include "vm/JSObject.h"
     32 #include "vm/PlainObject.h"    // js::PlainObject
     33 #include "vm/PromiseObject.h"  // js::PromiseObject, js::PromiseSlot_*
     34 #include "vm/SelfHosting.h"
     35 #include "vm/Warnings.h"  // js::WarnNumberASCII
     36 
     37 #include "debugger/DebugAPI-inl.h"
     38 #include "gc/StableCellHasher-inl.h"
     39 #include "vm/Compartment-inl.h"
     40 #include "vm/ErrorObject-inl.h"
     41 #include "vm/JSContext-inl.h"  // JSContext::check
     42 #include "vm/JSObject-inl.h"
     43 #include "vm/NativeObject-inl.h"
     44 
     45 using namespace js;
     46 
     47 static double MillisecondsSinceStartup() {
     48  auto now = mozilla::TimeStamp::Now();
     49  return (now - mozilla::TimeStamp::FirstTimeStamp()).ToMilliseconds();
     50 }
     51 
     52 constexpr auto HostDefinedDataIsOptimizedOut = nullptr;
     53 
     54 enum ResolutionMode { ResolveMode, RejectMode };
     55 
     56 /**
     57 * ES2023 draft rev 714fa3dd1e8237ae9c666146270f81880089eca5
     58 *
     59 * Promise Resolve Functions
     60 * https://tc39.es/ecma262/#sec-promise-resolve-functions
     61 */
     62 enum ResolveFunctionSlots {
     63  // NOTE: All slot represent [[AlreadyResolved]].[[Value]].
     64  //
     65  // The spec creates single record for [[AlreadyResolved]] and shares it
     66  // between Promise Resolve Function and Promise Reject Function.
     67  //
     68  //   Step 1. Let alreadyResolved be the Record { [[Value]]: false }.
     69  //   ...
     70  //   Step 6. Set resolve.[[AlreadyResolved]] to alreadyResolved.
     71  //   ...
     72  //   Step 11. Set reject.[[AlreadyResolved]] to alreadyResolved.
     73  //
     74  // We implement it by clearing all slots, both in
     75  // Promise Resolve Function and Promise Reject Function at the same time.
     76  //
     77  // If none of slots are undefined, [[AlreadyResolved]].[[Value]] is false.
     78  // If all slot are undefined, [[AlreadyResolved]].[[Value]] is true.
     79 
     80  // [[Promise]] slot.
     81  // A possibly-wrapped promise.
     82  ResolveFunctionSlot_Promise = 0,
     83 
     84  // The corresponding Promise Reject Function.
     85  ResolveFunctionSlot_RejectFunction,
     86 };
     87 
     88 /**
     89 * ES2023 draft rev 714fa3dd1e8237ae9c666146270f81880089eca5
     90 *
     91 * Promise Reject Functions
     92 * https://tc39.es/ecma262/#sec-promise-reject-functions
     93 */
     94 enum RejectFunctionSlots {
     95  // [[Promise]] slot.
     96  // A possibly-wrapped promise.
     97  RejectFunctionSlot_Promise = 0,
     98 
     99  // The corresponding Promise Resolve Function.
    100  RejectFunctionSlot_ResolveFunction,
    101 };
    102 
    103 // The promise combinator builtins such as Promise.all and Promise.allSettled
    104 // allocate one or two functions for each array element. These functions store
    105 // some state in extended slots.
    106 enum PromiseCombinatorElementFunctionSlots {
    107  // This slot stores either:
    108  //
    109  // - The [[Index]] slot (the array index) as Int32Value.
    110  //
    111  // - For the onRejected functions for Promise.allSettled, a pointer to the
    112  //   corresponding onFulfilled function stored as ObjectValue. In this case
    113  //   the slots on that function must be used instead because the
    114  //   [[AlreadyCalled]] flag must be shared by these two functions.
    115  PromiseCombinatorElementFunctionSlot_ElementIndexOrResolveFunc = 0,
    116 
    117  // This slot stores a pointer to the PromiseCombinatorDataHolder JS object.
    118  // It's also used to represent the [[AlreadyCalled]] flag: we set this slot to
    119  // UndefinedValue when [[AlreadyCalled]] is set to true in the spec.
    120  //
    121  // The onRejected functions for Promise.allSettled have a NullValue stored in
    122  // this slot. In this case the slot shouldn't be used because the
    123  // [[AlreadyCalled]] state must be shared by the two functions.
    124  PromiseCombinatorElementFunctionSlot_Data
    125 };
    126 
    127 enum ReactionJobSlots {
    128  ReactionJobSlot_ReactionRecord = 0,
    129 };
    130 
    131 // Extended function slots used to pass arguments through to either
    132 // PromiseResolveThenableJob, or PromiseResolveBuiltinThenableJob when calling
    133 // the built-in `then`.
    134 enum ThenableJobSlots {
    135  // The Promise to resolve using the given thenable.
    136  //
    137  // This can be a CCW when used for PromiseResolveThenableJob, otherwise it is
    138  // guaranteed not to be.
    139  ThenableJobSlot_Promise = 0,
    140 
    141  // The thenable to use as the receiver when calling the `then` function.
    142  //
    143  // This can be a CCW when used for PromiseResolveThenableJob, otherwise it is
    144  // guaranteed not to be.
    145  ThenableJobSlot_Thenable,
    146 
    147  // The handler to use as the Promise reaction, when not calling the built-in
    148  // `then`. It is a callable object that's guaranteed to be from the same
    149  // compartment as the PromiseReactionJob.
    150  ThenableJobSlot_Handler,
    151 
    152  ThenableJobSlot_Count
    153 };
    154 
    155 static_assert(size_t(ThenableJobSlot_Count) <=
    156              size_t(FunctionExtended::SlotCount));
    157 
    158 struct PromiseCapability {
    159  JSObject* promise = nullptr;
    160  JSObject* resolve = nullptr;
    161  JSObject* reject = nullptr;
    162 
    163  PromiseCapability() = default;
    164 
    165  void trace(JSTracer* trc);
    166 };
    167 
    168 void PromiseCapability::trace(JSTracer* trc) {
    169  if (promise) {
    170    TraceRoot(trc, &promise, "PromiseCapability::promise");
    171  }
    172  if (resolve) {
    173    TraceRoot(trc, &resolve, "PromiseCapability::resolve");
    174  }
    175  if (reject) {
    176    TraceRoot(trc, &reject, "PromiseCapability::reject");
    177  }
    178 }
    179 
    180 namespace js {
    181 
    182 template <typename Wrapper>
    183 class WrappedPtrOperations<PromiseCapability, Wrapper> {
    184  const PromiseCapability& capability() const {
    185    return static_cast<const Wrapper*>(this)->get();
    186  }
    187 
    188 public:
    189  HandleObject promise() const {
    190    return HandleObject::fromMarkedLocation(&capability().promise);
    191  }
    192  HandleObject resolve() const {
    193    return HandleObject::fromMarkedLocation(&capability().resolve);
    194  }
    195  HandleObject reject() const {
    196    return HandleObject::fromMarkedLocation(&capability().reject);
    197  }
    198 };
    199 
    200 template <typename Wrapper>
    201 class MutableWrappedPtrOperations<PromiseCapability, Wrapper>
    202    : public WrappedPtrOperations<PromiseCapability, Wrapper> {
    203  PromiseCapability& capability() { return static_cast<Wrapper*>(this)->get(); }
    204 
    205 public:
    206  MutableHandleObject promise() {
    207    return MutableHandleObject::fromMarkedLocation(&capability().promise);
    208  }
    209  MutableHandleObject resolve() {
    210    return MutableHandleObject::fromMarkedLocation(&capability().resolve);
    211  }
    212  MutableHandleObject reject() {
    213    return MutableHandleObject::fromMarkedLocation(&capability().reject);
    214  }
    215 };
    216 
    217 }  // namespace js
    218 
    219 struct PromiseCombinatorElements;
    220 
    221 class PromiseCombinatorDataHolder : public NativeObject {
    222  enum {
    223    Slot_Promise = 0,
    224    Slot_RemainingElements,
    225    Slot_ValuesArray,
    226    Slot_ResolveOrRejectFunction,
    227    SlotsCount,
    228  };
    229 
    230 public:
    231  static const JSClass class_;
    232  JSObject* promiseObj() { return &getFixedSlot(Slot_Promise).toObject(); }
    233  JSObject* resolveOrRejectObj() {
    234    return &getFixedSlot(Slot_ResolveOrRejectFunction).toObject();
    235  }
    236  Value valuesArray() { return getFixedSlot(Slot_ValuesArray); }
    237  int32_t remainingCount() {
    238    return getFixedSlot(Slot_RemainingElements).toInt32();
    239  }
    240  int32_t increaseRemainingCount() {
    241    int32_t remainingCount = getFixedSlot(Slot_RemainingElements).toInt32();
    242    remainingCount++;
    243    setFixedSlot(Slot_RemainingElements, Int32Value(remainingCount));
    244    return remainingCount;
    245  }
    246  int32_t decreaseRemainingCount() {
    247    int32_t remainingCount = getFixedSlot(Slot_RemainingElements).toInt32();
    248    remainingCount--;
    249    MOZ_ASSERT(remainingCount >= 0, "unpaired calls to decreaseRemainingCount");
    250    setFixedSlot(Slot_RemainingElements, Int32Value(remainingCount));
    251    return remainingCount;
    252  }
    253 
    254  static PromiseCombinatorDataHolder* New(
    255      JSContext* cx, HandleObject resultPromise,
    256      Handle<PromiseCombinatorElements> elements, HandleObject resolveOrReject);
    257 };
    258 
    259 const JSClass PromiseCombinatorDataHolder::class_ = {
    260    "PromiseCombinatorDataHolder",
    261    JSCLASS_HAS_RESERVED_SLOTS(SlotsCount),
    262 };
    263 
    264 // Smart pointer to the "F.[[Values]]" part of the state of a Promise.all or
    265 // Promise.allSettled invocation, or the "F.[[Errors]]" part of the state of a
    266 // Promise.any invocation. Copes with compartment issues when setting an
    267 // element.
    268 struct MOZ_STACK_CLASS PromiseCombinatorElements final {
    269  // Object value holding the elements array. The object can be a wrapper.
    270  Value value;
    271 
    272  // Unwrapped elements array. May not belong to the current compartment!
    273  ArrayObject* unwrappedArray = nullptr;
    274 
    275  // Set to true if the |setElement| method needs to wrap its input value.
    276  bool setElementNeedsWrapping = false;
    277 
    278  PromiseCombinatorElements() = default;
    279 
    280  void trace(JSTracer* trc);
    281 };
    282 
    283 void PromiseCombinatorElements::trace(JSTracer* trc) {
    284  TraceRoot(trc, &value, "PromiseCombinatorElements::value");
    285  if (unwrappedArray) {
    286    TraceRoot(trc, &unwrappedArray,
    287              "PromiseCombinatorElements::unwrappedArray");
    288  }
    289 }
    290 
    291 namespace js {
    292 
    293 template <typename Wrapper>
    294 class WrappedPtrOperations<PromiseCombinatorElements, Wrapper> {
    295  const PromiseCombinatorElements& elements() const {
    296    return static_cast<const Wrapper*>(this)->get();
    297  }
    298 
    299 public:
    300  HandleValue value() const {
    301    return HandleValue::fromMarkedLocation(&elements().value);
    302  }
    303 
    304  Handle<ArrayObject*> unwrappedArray() const {
    305    return Handle<ArrayObject*>::fromMarkedLocation(&elements().unwrappedArray);
    306  }
    307 };
    308 
    309 template <typename Wrapper>
    310 class MutableWrappedPtrOperations<PromiseCombinatorElements, Wrapper>
    311    : public WrappedPtrOperations<PromiseCombinatorElements, Wrapper> {
    312  PromiseCombinatorElements& elements() {
    313    return static_cast<Wrapper*>(this)->get();
    314  }
    315 
    316 public:
    317  MutableHandleValue value() {
    318    return MutableHandleValue::fromMarkedLocation(&elements().value);
    319  }
    320 
    321  MutableHandle<ArrayObject*> unwrappedArray() {
    322    return MutableHandle<ArrayObject*>::fromMarkedLocation(
    323        &elements().unwrappedArray);
    324  }
    325 
    326  void initialize(ArrayObject* arrayObj) {
    327    unwrappedArray().set(arrayObj);
    328    value().setObject(*arrayObj);
    329 
    330    // |needsWrapping| isn't tracked here, because all modifications on the
    331    // initial elements don't require any wrapping.
    332  }
    333 
    334  void initialize(PromiseCombinatorDataHolder* data, ArrayObject* arrayObj,
    335                  bool needsWrapping) {
    336    unwrappedArray().set(arrayObj);
    337    value().set(data->valuesArray());
    338    elements().setElementNeedsWrapping = needsWrapping;
    339  }
    340 
    341  [[nodiscard]] bool pushUndefined(JSContext* cx) {
    342    // Helper for the AutoRealm we need to work with |array|. We mostly do this
    343    // for performance; we could go ahead and do the define via a cross-
    344    // compartment proxy instead...
    345    AutoRealm ar(cx, unwrappedArray());
    346 
    347    Handle<ArrayObject*> arrayObj = unwrappedArray();
    348    return js::NewbornArrayPush(cx, arrayObj, UndefinedValue());
    349  }
    350 
    351  // `Promise.all` Resolve Element Functions
    352  // Step 9. Set values[index] to x.
    353  //
    354  // `Promise.allSettled` Resolve Element Functions
    355  // `Promise.allSettled` Reject Element Functions
    356  // Step 12. Set values[index] to obj.
    357  //
    358  // `Promise.any` Reject Element Functions
    359  // Step 9. Set errors[index] to x.
    360  //
    361  // These handler functions are always created in the compartment of the
    362  // Promise.all/allSettled/any function, which isn't necessarily the same
    363  // compartment as unwrappedArray as explained in NewPromiseCombinatorElements.
    364  // So before storing |val| we may need to enter unwrappedArray's compartment.
    365  [[nodiscard]] bool setElement(JSContext* cx, uint32_t index,
    366                                HandleValue val) {
    367    // The index is guaranteed to be initialized to `undefined`.
    368    MOZ_ASSERT(unwrappedArray()->getDenseElement(index).isUndefined());
    369 
    370    if (elements().setElementNeedsWrapping) {
    371      AutoRealm ar(cx, unwrappedArray());
    372 
    373      RootedValue rootedVal(cx, val);
    374      if (!cx->compartment()->wrap(cx, &rootedVal)) {
    375        return false;
    376      }
    377      unwrappedArray()->setDenseElement(index, rootedVal);
    378    } else {
    379      unwrappedArray()->setDenseElement(index, val);
    380    }
    381    return true;
    382  }
    383 };
    384 
    385 }  // namespace js
    386 
    387 PromiseCombinatorDataHolder* PromiseCombinatorDataHolder::New(
    388    JSContext* cx, HandleObject resultPromise,
    389    Handle<PromiseCombinatorElements> elements, HandleObject resolveOrReject) {
    390  auto* dataHolder = NewBuiltinClassInstance<PromiseCombinatorDataHolder>(cx);
    391  if (!dataHolder) {
    392    return nullptr;
    393  }
    394 
    395  cx->check(resultPromise, elements.value(), resolveOrReject);
    396 
    397  dataHolder->initFixedSlot(Slot_Promise, ObjectValue(*resultPromise));
    398  dataHolder->initFixedSlot(Slot_RemainingElements, Int32Value(1));
    399  dataHolder->initFixedSlot(Slot_ValuesArray, elements.value());
    400  dataHolder->initFixedSlot(Slot_ResolveOrRejectFunction,
    401                            ObjectValue(*resolveOrReject));
    402  return dataHolder;
    403 }
    404 
    405 namespace {
    406 // Generator used by PromiseObject::getID.
    407 mozilla::Atomic<uint64_t> gIDGenerator(0);
    408 }  // namespace
    409 
    410 // Returns true if the following properties haven't been mutated:
    411 // - On the original Promise.prototype object: "constructor" and "then"
    412 // - On the original Promise constructor: "resolve" and @@species
    413 static bool HasDefaultPromiseProperties(JSContext* cx) {
    414  return cx->realm()->realmFuses.optimizePromiseLookupFuse.intact();
    415 }
    416 
    417 static bool IsPromiseWithDefaultProperties(PromiseObject* promise,
    418                                           JSContext* cx) {
    419  if (!HasDefaultPromiseProperties(cx)) {
    420    return false;
    421  }
    422 
    423  // Ensure the promise's prototype is the original Promise.prototype object.
    424  JSObject* proto = cx->global()->maybeGetPrototype(JSProto_Promise);
    425  if (!proto || promise->staticPrototype() != proto) {
    426    return false;
    427  }
    428 
    429  // Ensure `promise` doesn't define any own properties. This serves as a
    430  // quick check to make sure `promise` doesn't define an own "constructor"
    431  // or "then" property which may shadow Promise.prototype.constructor or
    432  // Promise.prototype.then.
    433  return promise->empty();
    434 }
    435 
    436 class PromiseDebugInfo : public NativeObject {
    437 private:
    438  enum Slots {
    439    Slot_AllocationSite,
    440    Slot_ResolutionSite,
    441    Slot_AllocationTime,
    442    Slot_ResolutionTime,
    443    Slot_Id,
    444    SlotCount
    445  };
    446 
    447 public:
    448  static const JSClass class_;
    449  static PromiseDebugInfo* create(JSContext* cx,
    450                                  Handle<PromiseObject*> promise) {
    451    Rooted<PromiseDebugInfo*> debugInfo(
    452        cx, NewBuiltinClassInstance<PromiseDebugInfo>(cx));
    453    if (!debugInfo) {
    454      return nullptr;
    455    }
    456 
    457    RootedObject stack(cx);
    458    if (!JS::CaptureCurrentStack(cx, &stack,
    459                                 JS::StackCapture(JS::AllFrames()))) {
    460      return nullptr;
    461    }
    462    debugInfo->setFixedSlot(Slot_AllocationSite, ObjectOrNullValue(stack));
    463    debugInfo->setFixedSlot(Slot_ResolutionSite, NullValue());
    464    debugInfo->setFixedSlot(Slot_AllocationTime,
    465                            DoubleValue(MillisecondsSinceStartup()));
    466    debugInfo->setFixedSlot(Slot_ResolutionTime, NumberValue(0));
    467    promise->setFixedSlot(PromiseSlot_DebugInfo, ObjectValue(*debugInfo));
    468 
    469    return debugInfo;
    470  }
    471 
    472  static PromiseDebugInfo* FromPromise(PromiseObject* promise) {
    473    Value val = promise->getFixedSlot(PromiseSlot_DebugInfo);
    474    if (val.isObject()) {
    475      return &val.toObject().as<PromiseDebugInfo>();
    476    }
    477    return nullptr;
    478  }
    479 
    480  /**
    481   * Returns the given PromiseObject's process-unique ID.
    482   * The ID is lazily assigned when first queried, and then either stored
    483   * in the DebugInfo slot if no debug info was recorded for this Promise,
    484   * or in the Id slot of the DebugInfo object.
    485   */
    486  static uint64_t id(PromiseObject* promise) {
    487    Value idVal(promise->getFixedSlot(PromiseSlot_DebugInfo));
    488    if (idVal.isUndefined()) {
    489      idVal.setDouble(++gIDGenerator);
    490      promise->setFixedSlot(PromiseSlot_DebugInfo, idVal);
    491    } else if (idVal.isObject()) {
    492      PromiseDebugInfo* debugInfo = FromPromise(promise);
    493      idVal = debugInfo->getFixedSlot(Slot_Id);
    494      if (idVal.isUndefined()) {
    495        idVal.setDouble(++gIDGenerator);
    496        debugInfo->setFixedSlot(Slot_Id, idVal);
    497      }
    498    }
    499    return uint64_t(idVal.toNumber());
    500  }
    501 
    502  double allocationTime() {
    503    return getFixedSlot(Slot_AllocationTime).toNumber();
    504  }
    505  double resolutionTime() {
    506    return getFixedSlot(Slot_ResolutionTime).toNumber();
    507  }
    508  JSObject* allocationSite() {
    509    return getFixedSlot(Slot_AllocationSite).toObjectOrNull();
    510  }
    511  JSObject* resolutionSite() {
    512    return getFixedSlot(Slot_ResolutionSite).toObjectOrNull();
    513  }
    514 
    515  // The |unwrappedRejectionStack| parameter should only be set on promise
    516  // rejections and should be the stack of the exception that caused the promise
    517  // to be rejected. If the |unwrappedRejectionStack| is null, the current stack
    518  // will be used instead. This is also the default behavior for fulfilled
    519  // promises.
    520  static void setResolutionInfo(JSContext* cx, Handle<PromiseObject*> promise,
    521                                Handle<SavedFrame*> unwrappedRejectionStack) {
    522    MOZ_ASSERT_IF(unwrappedRejectionStack,
    523                  promise->state() == JS::PromiseState::Rejected);
    524 
    525    if (!JS::IsAsyncStackCaptureEnabledForRealm(cx)) {
    526      return;
    527    }
    528 
    529    // If async stacks weren't enabled and the Promise's global wasn't a
    530    // debuggee when the Promise was created, we won't have a debugInfo
    531    // object. We still want to capture the resolution stack, so we
    532    // create the object now and change it's slots' values around a bit.
    533    Rooted<PromiseDebugInfo*> debugInfo(cx, FromPromise(promise));
    534    if (!debugInfo) {
    535      RootedValue idVal(cx, promise->getFixedSlot(PromiseSlot_DebugInfo));
    536      debugInfo = create(cx, promise);
    537      if (!debugInfo) {
    538        cx->clearPendingException();
    539        return;
    540      }
    541 
    542      // The current stack was stored in the AllocationSite slot, move
    543      // it to ResolutionSite as that's what it really is.
    544      debugInfo->setFixedSlot(Slot_ResolutionSite,
    545                              debugInfo->getFixedSlot(Slot_AllocationSite));
    546      debugInfo->setFixedSlot(Slot_AllocationSite, NullValue());
    547 
    548      // There's no good default for a missing AllocationTime, so
    549      // instead of resetting that, ensure that it's the same as
    550      // ResolutionTime, so that the diff shows as 0, which isn't great,
    551      // but bearable.
    552      debugInfo->setFixedSlot(Slot_ResolutionTime,
    553                              debugInfo->getFixedSlot(Slot_AllocationTime));
    554 
    555      // The Promise's ID might've been queried earlier, in which case
    556      // it's stored in the DebugInfo slot. We saved that earlier, so
    557      // now we can store it in the right place (or leave it as
    558      // undefined if it wasn't ever initialized.)
    559      debugInfo->setFixedSlot(Slot_Id, idVal);
    560      return;
    561    }
    562 
    563    RootedObject stack(cx, unwrappedRejectionStack);
    564    if (stack) {
    565      // The exception stack is always unwrapped so it might be in
    566      // a different compartment.
    567      if (!cx->compartment()->wrap(cx, &stack)) {
    568        cx->clearPendingException();
    569        return;
    570      }
    571    } else {
    572      if (!JS::CaptureCurrentStack(cx, &stack,
    573                                   JS::StackCapture(JS::AllFrames()))) {
    574        cx->clearPendingException();
    575        return;
    576      }
    577    }
    578 
    579    debugInfo->setFixedSlot(Slot_ResolutionSite, ObjectOrNullValue(stack));
    580    debugInfo->setFixedSlot(Slot_ResolutionTime,
    581                            DoubleValue(MillisecondsSinceStartup()));
    582  }
    583 
    584 #if defined(DEBUG) || defined(JS_JITSPEW)
    585  void dumpOwnFields(js::JSONPrinter& json) const;
    586 #endif
    587 };
    588 
    589 const JSClass PromiseDebugInfo::class_ = {
    590    "PromiseDebugInfo",
    591    JSCLASS_HAS_RESERVED_SLOTS(SlotCount),
    592 };
    593 
    594 double PromiseObject::allocationTime() {
    595  auto debugInfo = PromiseDebugInfo::FromPromise(this);
    596  if (debugInfo) {
    597    return debugInfo->allocationTime();
    598  }
    599  return 0;
    600 }
    601 
    602 double PromiseObject::resolutionTime() {
    603  auto debugInfo = PromiseDebugInfo::FromPromise(this);
    604  if (debugInfo) {
    605    return debugInfo->resolutionTime();
    606  }
    607  return 0;
    608 }
    609 
    610 JSObject* PromiseObject::allocationSite() {
    611  auto debugInfo = PromiseDebugInfo::FromPromise(this);
    612  if (debugInfo) {
    613    return debugInfo->allocationSite();
    614  }
    615  return nullptr;
    616 }
    617 
    618 JSObject* PromiseObject::resolutionSite() {
    619  auto debugInfo = PromiseDebugInfo::FromPromise(this);
    620  if (debugInfo) {
    621    JSObject* site = debugInfo->resolutionSite();
    622    if (site && !JS_IsDeadWrapper(site)) {
    623      MOZ_ASSERT(UncheckedUnwrap(site)->is<SavedFrame>());
    624      return site;
    625    }
    626  }
    627  return nullptr;
    628 }
    629 
    630 /**
    631 * Wrapper for GetAndClearExceptionAndStack that handles cases where
    632 * no exception is pending, but an error occurred.
    633 * This can be the case if an OOM was encountered while throwing the error.
    634 */
    635 static bool MaybeGetAndClearExceptionAndStack(
    636    JSContext* cx, MutableHandleValue rval, MutableHandle<SavedFrame*> stack) {
    637  if (!cx->isExceptionPending()) {
    638    return false;
    639  }
    640 
    641  return GetAndClearExceptionAndStack(cx, rval, stack);
    642 }
    643 
    644 [[nodiscard]] static bool CallPromiseRejectFunction(
    645    JSContext* cx, HandleObject rejectFun, HandleValue reason,
    646    HandleObject promiseObj, Handle<SavedFrame*> unwrappedRejectionStack,
    647    UnhandledRejectionBehavior behavior);
    648 
    649 /**
    650 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
    651 *
    652 * IfAbruptRejectPromise ( value, capability )
    653 * https://tc39.es/ecma262/#sec-ifabruptrejectpromise
    654 *
    655 * Steps 1.a-b.
    656 *
    657 * Extracting all of this internal spec algorithm into a helper function would
    658 * be tedious, so the check in step 1 and the entirety of step 2 aren't
    659 * included.
    660 */
    661 bool js::AbruptRejectPromise(JSContext* cx, CallArgs& args,
    662                             HandleObject promiseObj, HandleObject reject) {
    663  // Step 1.a. Perform
    664  //           ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
    665  RootedValue reason(cx);
    666  Rooted<SavedFrame*> stack(cx);
    667  if (!MaybeGetAndClearExceptionAndStack(cx, &reason, &stack)) {
    668    return false;
    669  }
    670 
    671  if (!CallPromiseRejectFunction(cx, reject, reason, promiseObj, stack,
    672                                 UnhandledRejectionBehavior::Report)) {
    673    return false;
    674  }
    675 
    676  // Step 1.b. Return capability.[[Promise]].
    677  args.rval().setObject(*promiseObj);
    678  return true;
    679 }
    680 
    681 static bool AbruptRejectPromise(JSContext* cx, CallArgs& args,
    682                                Handle<PromiseCapability> capability) {
    683  return AbruptRejectPromise(cx, args, capability.promise(),
    684                             capability.reject());
    685 }
    686 
    687 class MicroTaskEntry : public NativeObject {
    688 protected:
    689  enum Slots {
    690    // Shared slots:
    691    Promise = 0,      // see comment in PromiseReactionRecord
    692    HostDefinedData,  // See comment in PromiseReactionRecord
    693 
    694    // Only needed for microtask jobs
    695    AllocationStack,
    696    HostDefinedGlobalRepresentative,
    697    SlotCount,
    698  };
    699 
    700 public:
    701  JSObject* promise() const {
    702    return getFixedSlot(Slots::Promise).toObjectOrNull();
    703  }
    704 
    705  void setPromise(JSObject* obj) {
    706    setFixedSlot(Slots::Promise, ObjectOrNullValue(obj));
    707  }
    708 
    709  Value getHostDefinedData() const {
    710    return getFixedSlot(Slots::HostDefinedData);
    711  }
    712 
    713  void setHostDefinedData(const Value& val) {
    714    setFixedSlot(Slots::HostDefinedData, val);
    715  }
    716 
    717  JSObject* allocationStack() const {
    718    return getFixedSlot(Slots::AllocationStack).toObjectOrNull();
    719  }
    720 
    721  void setAllocationStack(JSObject* stack) {
    722    setFixedSlot(Slots::AllocationStack, ObjectOrNullValue(stack));
    723  }
    724 
    725  JSObject* hostDefinedGlobalRepresentative() const {
    726    Value v = getFixedSlot(Slots::HostDefinedGlobalRepresentative);
    727    return v.isObjectOrNull() ? v.toObjectOrNull() : nullptr;
    728  }
    729 
    730  void setHostDefinedGlobalRepresentative(JSObject* global) {
    731    setFixedSlot(Slots::HostDefinedGlobalRepresentative,
    732                 ObjectOrNullValue(global));
    733  }
    734 };
    735 
    736 /**
    737 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
    738 *
    739 * PromiseReaction Records
    740 * https://tc39.es/ecma262/#sec-promisereaction-records
    741 */
    742 class PromiseReactionRecord : public MicroTaskEntry {
    743  // If this flag is set, this reaction record is already enqueued to the
    744  // job queue, and the spec's [[Type]] field is represented by
    745  // REACTION_FLAG_FULFILLED flag.
    746  //
    747  // If this flag isn't yet set, [[Type]] field is undefined.
    748  static constexpr uint32_t REACTION_FLAG_RESOLVED = 0x1;
    749 
    750  // This bit is valid only when REACTION_FLAG_RESOLVED flag is set.
    751  //
    752  // If this flag is set, [[Type]] field is Fulfill.
    753  // If this flag isn't set, [[Type]] field is Reject.
    754  static constexpr uint32_t REACTION_FLAG_FULFILLED = 0x2;
    755 
    756  // If this flag is set, this reaction record is created for resolving
    757  // one promise P1 to another promise P2, and
    758  // Slot::GeneratorOrPromiseToResolveOrAsyncFromSyncIterator slot
    759  // holds P2.
    760  static constexpr uint32_t REACTION_FLAG_DEFAULT_RESOLVING_HANDLER = 0x4;
    761 
    762  // If this flag is set, this reaction record is created for async function
    763  // and Slot::GeneratorOrPromiseToResolveOrAsyncFromSyncIterator
    764  // slot holds internal generator object of the async function.
    765  static constexpr uint32_t REACTION_FLAG_ASYNC_FUNCTION = 0x8;
    766 
    767  // If this flag is set, this reaction record is created for async generator
    768  // and Slot::GeneratorOrPromiseToResolveOrAsyncFromSyncIterator
    769  // slot holds the async generator object of the async generator.
    770  static constexpr uint32_t REACTION_FLAG_ASYNC_GENERATOR = 0x10;
    771 
    772  // If this flag is set, this reaction record is created only for providing
    773  // information to debugger.
    774  static constexpr uint32_t REACTION_FLAG_DEBUGGER_DUMMY = 0x20;
    775 
    776  // This bit is valid only when the promise object is optimized out
    777  // for the reaction.
    778  //
    779  // If this flag is set, unhandled rejection should be ignored.
    780  // Otherwise, promise object should be created on-demand for unhandled
    781  // rejection.
    782  static constexpr uint32_t REACTION_FLAG_IGNORE_UNHANDLED_REJECTION = 0x40;
    783 
    784  // If this flag is set, this reaction record is created for async-from-sync
    785  // iterators and
    786  // Slot::GeneratorOrPromiseToResolveOrAsyncFromSyncIterator slot
    787  // holds the async-from-sync iterator object.
    788  static constexpr uint32_t REACTION_FLAG_ASYNC_FROM_SYNC_ITERATOR = 0x80;
    789 
    790 public:
    791  enum Slots {
    792    // This is the promise-like object that gets resolved with the result of
    793    // this reaction, if any. If this reaction record was created with .then or
    794    // .catch, this is the promise that .then or .catch returned.
    795    //
    796    // The spec says that a PromiseReaction record has a [[Capability]] field
    797    // whose value is either undefined or a PromiseCapability record, but we
    798    // just store the PromiseCapability's fields directly in this object. This
    799    // is the
    800    // capability's [[Promise]] field; its [[Resolve]] and [[Reject]] fields are
    801    // stored in Slot::Resolve and Slot::Reject.
    802    //
    803    // This can be 'null' in reaction records created for a few situations:
    804    //
    805    // - When you resolve one promise to another. When you pass a promise P1 to
    806    //   the 'fulfill' function of a promise P2, so that resolving P1 resolves
    807    //   P2 in the same way, P1 gets a reaction record with the
    808    //   REACTION_FLAG_DEFAULT_RESOLVING_HANDLER flag set and whose
    809    //   Slots::GeneratorOrPromiseToResolveOrAsyncFromSyncIterator
    810    //   slot holds P2.
    811    //
    812    // - When you await a promise. When an async function or generator awaits a
    813    //   value V, then the await expression generates an internal promise P,
    814    //   resolves it to V, and then gives P a reaction record with the
    815    //   REACTION_FLAG_ASYNC_FUNCTION or REACTION_FLAG_ASYNC_GENERATOR flag set
    816    //   and whose Slot::GeneratorOrPromiseToResolveOrAsyncFromSyncIterator
    817    //   slot holds the generator object. (Typically V is a promise, so
    818    //   resolving P to V gives V a REACTION_FLAGS_DEFAULT_RESOLVING_HANDLER
    819    //   reaction
    820    //   record as described above.)
    821    //
    822    // - When JS::AddPromiseReactions{,IgnoringUnhandledRejection} cause the
    823    //   reaction to be created. (These functions act as if they had created a
    824    //   promise to invoke the appropriate provided reaction function, without
    825    //   actually allocating a promise for them.)
    826    Promise = MicroTaskEntry::Slots::Promise,
    827 
    828    // The host defined data for this reaction record. Can be null.
    829    // See step 5 in https://html.spec.whatwg.org/#hostmakejobcallback
    830    HostDefinedData = MicroTaskEntry::Slots::HostDefinedData,
    831 
    832    // < Invisibly here are the microtask job slots from the parent class
    833    // MicroTask. >
    834 
    835    // A slot holding an object from the realm where we need to execute
    836    // the reaction job. This may be a CCW. We don't store the global
    837    // of the realm directly because wrappers to globals can change
    838    // globals, which breaks code.
    839    EnqueueGlobalRepresentative = MicroTaskEntry::Slots::SlotCount,
    840 
    841    // The [[Handler]] field(s) of a PromiseReaction record. We create a
    842    // single reaction record for fulfillment and rejection, therefore our
    843    // PromiseReaction implementation needs two [[Handler]] fields.
    844    //
    845    // The slot value is either a callable object, an integer constant from
    846    // the |PromiseHandler| enum, or null. If the value is null, either the
    847    // REACTION_FLAG_DEBUGGER_DUMMY or the
    848    // REACTION_FLAG_DEFAULT_RESOLVING_HANDLER flag must be set.
    849    //
    850    // After setting the target state for a PromiseReaction, the slot of the
    851    // no longer used handler gets reused to store the argument of the active
    852    // handler.
    853    OnFulfilled,
    854    OnRejectedArg = OnFulfilled,
    855    OnRejected,
    856    OnFulfilledArg = OnRejected,
    857 
    858    // The functions to resolve or reject the promise. Matches the
    859    // [[Capability]].[[Resolve]] and [[Capability]].[[Reject]] fields from
    860    // the spec.
    861    //
    862    // The slot values are either callable objects or null, but the latter
    863    // case is only allowed if the promise is either a built-in Promise object
    864    // or null.
    865    Resolve,
    866    Reject,
    867 
    868    // Bitmask of the REACTION_FLAG values.
    869    Flags,
    870 
    871    // Additional slot to store extra data for specific reaction record types.
    872    //
    873    // - When the REACTION_FLAG_ASYNC_FUNCTION flag is set, this slot stores
    874    //   the (internal) generator object for this promise reaction.
    875    // - When the REACTION_FLAG_ASYNC_GENERATOR flag is set, this slot stores
    876    //   the async generator object for this promise reaction.
    877    // - When the REACTION_FLAG_DEFAULT_RESOLVING_HANDLER flag is set, this
    878    //   slot stores the promise to resolve when conceptually "calling" the
    879    //   OnFulfilled or OnRejected handlers.
    880    // - When the REACTION_FLAG_ASYNC_FROM_SYNC_ITERATOR is set, this slot
    881    // stores
    882    //   the async-from-sync iterator object.
    883    GeneratorOrPromiseToResolveOrAsyncFromSyncIterator,
    884 
    885    SlotCount,
    886  };
    887 
    888 private:
    889  template <typename KnownF, typename UnknownF>
    890  static void forEachReactionFlag(uint32_t flags, KnownF known,
    891                                  UnknownF unknown);
    892 
    893  void setFlagOnInitialState(uint32_t flag) {
    894    int32_t flags = this->flags();
    895    MOZ_ASSERT(flags == 0, "Can't modify with non-default flags");
    896    flags |= flag;
    897    setFixedSlot(Slots::Flags, Int32Value(flags));
    898  }
    899 
    900  uint32_t handlerSlot() {
    901    MOZ_ASSERT(targetState() != JS::PromiseState::Pending);
    902    return targetState() == JS::PromiseState::Fulfilled ? Slots::OnFulfilled
    903                                                        : Slots::OnRejected;
    904  }
    905 
    906  uint32_t handlerArgSlot() {
    907    MOZ_ASSERT(targetState() != JS::PromiseState::Pending);
    908    return targetState() == JS::PromiseState::Fulfilled ? Slots::OnFulfilledArg
    909                                                        : Slots::OnRejectedArg;
    910  }
    911 
    912 public:
    913  static const JSClass class_;
    914 
    915  int32_t flags() const { return getFixedSlot(Slots::Flags).toInt32(); }
    916  JS::PromiseState targetState() const {
    917    int32_t flags = this->flags();
    918    if (!(flags & REACTION_FLAG_RESOLVED)) {
    919      return JS::PromiseState::Pending;
    920    }
    921    return flags & REACTION_FLAG_FULFILLED ? JS::PromiseState::Fulfilled
    922                                           : JS::PromiseState::Rejected;
    923  }
    924  void setTargetStateAndHandlerArg(JS::PromiseState state, const Value& arg) {
    925    MOZ_ASSERT(targetState() == JS::PromiseState::Pending);
    926    MOZ_ASSERT(state != JS::PromiseState::Pending,
    927               "Can't revert a reaction to pending.");
    928 
    929    int32_t flags = this->flags();
    930    flags |= REACTION_FLAG_RESOLVED;
    931    if (state == JS::PromiseState::Fulfilled) {
    932      flags |= REACTION_FLAG_FULFILLED;
    933    }
    934 
    935    setFixedSlot(Slots::Flags, Int32Value(flags));
    936    setFixedSlot(handlerArgSlot(), arg);
    937  }
    938 
    939  void setShouldIgnoreUnhandledRejection() {
    940    setFlagOnInitialState(REACTION_FLAG_IGNORE_UNHANDLED_REJECTION);
    941  }
    942  UnhandledRejectionBehavior unhandledRejectionBehavior() const {
    943    int32_t flags = this->flags();
    944    return (flags & REACTION_FLAG_IGNORE_UNHANDLED_REJECTION)
    945               ? UnhandledRejectionBehavior::Ignore
    946               : UnhandledRejectionBehavior::Report;
    947  }
    948 
    949  void setIsDefaultResolvingHandler(PromiseObject* promiseToResolve) {
    950    setFlagOnInitialState(REACTION_FLAG_DEFAULT_RESOLVING_HANDLER);
    951    setFixedSlot(Slots::GeneratorOrPromiseToResolveOrAsyncFromSyncIterator,
    952                 ObjectValue(*promiseToResolve));
    953  }
    954  bool isDefaultResolvingHandler() const {
    955    int32_t flags = this->flags();
    956    return flags & REACTION_FLAG_DEFAULT_RESOLVING_HANDLER;
    957  }
    958  PromiseObject* defaultResolvingPromise() {
    959    MOZ_ASSERT(isDefaultResolvingHandler());
    960    const Value& promiseToResolve =
    961        getFixedSlot(Slots::GeneratorOrPromiseToResolveOrAsyncFromSyncIterator);
    962    return &promiseToResolve.toObject().as<PromiseObject>();
    963  }
    964 
    965  void setIsAsyncFunction(AsyncFunctionGeneratorObject* genObj) {
    966    MOZ_ASSERT(realm() == genObj->nonCCWRealm());
    967    setFlagOnInitialState(REACTION_FLAG_ASYNC_FUNCTION);
    968    setFixedSlot(Slots::GeneratorOrPromiseToResolveOrAsyncFromSyncIterator,
    969                 ObjectValue(*genObj));
    970  }
    971  bool isAsyncFunction() const {
    972    int32_t flags = this->flags();
    973    return flags & REACTION_FLAG_ASYNC_FUNCTION;
    974  }
    975  AsyncFunctionGeneratorObject* asyncFunctionGenerator() {
    976    MOZ_ASSERT(isAsyncFunction());
    977    const Value& generator =
    978        getFixedSlot(Slots::GeneratorOrPromiseToResolveOrAsyncFromSyncIterator);
    979    AsyncFunctionGeneratorObject* res =
    980        &generator.toObject().as<AsyncFunctionGeneratorObject>();
    981    MOZ_RELEASE_ASSERT(realm() == res->realm());
    982    return res;
    983  }
    984 
    985  void setIsAsyncGenerator(AsyncGeneratorObject* generator) {
    986    setFlagOnInitialState(REACTION_FLAG_ASYNC_GENERATOR);
    987    setFixedSlot(Slots::GeneratorOrPromiseToResolveOrAsyncFromSyncIterator,
    988                 ObjectValue(*generator));
    989  }
    990  bool isAsyncGenerator() const {
    991    int32_t flags = this->flags();
    992    return flags & REACTION_FLAG_ASYNC_GENERATOR;
    993  }
    994  AsyncGeneratorObject* asyncGenerator() {
    995    MOZ_ASSERT(isAsyncGenerator());
    996    const Value& generator =
    997        getFixedSlot(Slots::GeneratorOrPromiseToResolveOrAsyncFromSyncIterator);
    998    return &generator.toObject().as<AsyncGeneratorObject>();
    999  }
   1000 
   1001  void setIsAsyncFromSyncIterator(AsyncFromSyncIteratorObject* iterator) {
   1002    setFlagOnInitialState(REACTION_FLAG_ASYNC_FROM_SYNC_ITERATOR);
   1003    setFixedSlot(Slots::GeneratorOrPromiseToResolveOrAsyncFromSyncIterator,
   1004                 ObjectValue(*iterator));
   1005  }
   1006  bool isAsyncFromSyncIterator() const {
   1007    int32_t flags = this->flags();
   1008    return flags & REACTION_FLAG_ASYNC_FROM_SYNC_ITERATOR;
   1009  }
   1010  AsyncFromSyncIteratorObject* asyncFromSyncIterator() {
   1011    MOZ_ASSERT(isAsyncFromSyncIterator());
   1012    const Value& iterator =
   1013        getFixedSlot(Slots::GeneratorOrPromiseToResolveOrAsyncFromSyncIterator);
   1014    return &iterator.toObject().as<AsyncFromSyncIteratorObject>();
   1015  }
   1016 
   1017  void setIsDebuggerDummy() {
   1018    setFlagOnInitialState(REACTION_FLAG_DEBUGGER_DUMMY);
   1019  }
   1020  bool isDebuggerDummy() const {
   1021    int32_t flags = this->flags();
   1022    return flags & REACTION_FLAG_DEBUGGER_DUMMY;
   1023  }
   1024 
   1025  Value handler() {
   1026    MOZ_ASSERT(targetState() != JS::PromiseState::Pending);
   1027    return getFixedSlot(handlerSlot());
   1028  }
   1029  Value handlerArg() {
   1030    MOZ_ASSERT(targetState() != JS::PromiseState::Pending);
   1031    return getFixedSlot(handlerArgSlot());
   1032  }
   1033 
   1034  JSObject* getAndClearHostDefinedData() {
   1035    JSObject* obj = getFixedSlot(Slots::HostDefinedData).toObjectOrNull();
   1036    setFixedSlot(Slots::HostDefinedData, UndefinedValue());
   1037    return obj;
   1038  }
   1039 
   1040  JSObject* enqueueGlobalRepresentative() const {
   1041    return getFixedSlot(Slots::EnqueueGlobalRepresentative).toObjectOrNull();
   1042  }
   1043  void setEnqueueGlobalRepresentative(JSObject* obj) {
   1044    setFixedSlot(Slots::EnqueueGlobalRepresentative, ObjectOrNullValue(obj));
   1045  }
   1046 
   1047 #if defined(DEBUG) || defined(JS_JITSPEW)
   1048  void dumpOwnFields(js::JSONPrinter& json) const;
   1049 #endif
   1050 };
   1051 
   1052 const JSClass PromiseReactionRecord::class_ = {
   1053    "PromiseReactionRecord",
   1054    JSCLASS_HAS_RESERVED_SLOTS(Slots::SlotCount),
   1055 };
   1056 
   1057 class ThenableJob : public MicroTaskEntry {
   1058 protected:
   1059  enum Slots {
   1060    // These slots come directoy after the MicroTaskEntry slots.
   1061    Thenable = MicroTaskEntry::Slots::SlotCount,
   1062    Then,
   1063    Callback,
   1064    SlotCount
   1065  };
   1066 
   1067 public:
   1068  static const JSClass class_;
   1069 
   1070  enum TargetFunction : int32_t {
   1071    PromiseResolveThenableJob,
   1072    PromiseResolveBuiltinThenableJob
   1073  };
   1074 
   1075  Value thenable() const { return getFixedSlot(Slots::Thenable); }
   1076 
   1077  void setThenable(const Value& val) { setFixedSlot(Slots::Thenable, val); }
   1078 
   1079  JSObject* then() const { return getFixedSlot(Slots::Then).toObjectOrNull(); }
   1080 
   1081  void setThen(JSObject* obj) {
   1082    setFixedSlot(Slots::Then, ObjectOrNullValue(obj));
   1083  }
   1084 
   1085  TargetFunction targetFunction() const {
   1086    return static_cast<TargetFunction>(getFixedSlot(Slots::Callback).toInt32());
   1087  }
   1088  void setTargetFunction(TargetFunction target) {
   1089    setFixedSlot(Slots::Callback, JS::Int32Value(static_cast<int32_t>(target)));
   1090  }
   1091 };
   1092 
   1093 const JSClass ThenableJob::class_ = {
   1094    "ThenableJob",
   1095    JSCLASS_HAS_RESERVED_SLOTS(ThenableJob::SlotCount),
   1096 };
   1097 
   1098 ThenableJob* NewThenableJob(JSContext* cx, ThenableJob::TargetFunction target,
   1099                            HandleObject promise, HandleValue thenable,
   1100                            HandleObject then, HandleObject hostDefinedData) {
   1101  // MG:XXX: Boy isn't it silly that we have to root here, only to get the
   1102  // allocation site...
   1103  RootedObject stack(
   1104      cx, JS::MaybeGetPromiseAllocationSiteFromPossiblyWrappedPromise(promise));
   1105  if (!cx->compartment()->wrap(cx, &stack)) {
   1106    return nullptr;
   1107  }
   1108 
   1109  // MG:XXX: Wrapping needs to be delegated to callers I think.
   1110  RootedObject hostDefined(cx, hostDefinedData);
   1111  if (!cx->compartment()->wrap(cx, &hostDefined)) {
   1112    return nullptr;
   1113  }
   1114  auto* job = NewBuiltinClassInstance<ThenableJob>(cx);
   1115  if (!job) {
   1116    return nullptr;
   1117  }
   1118  job->setPromise(promise);
   1119  job->setThen(then);
   1120  job->setThenable(thenable);
   1121  job->setTargetFunction(target);
   1122  job->setHostDefinedData(ObjectOrNullValue(hostDefined));
   1123  job->setAllocationStack(stack);
   1124 
   1125  return job;
   1126 }
   1127 
   1128 static void AddPromiseFlags(PromiseObject& promise, int32_t flag) {
   1129  int32_t flags = promise.flags();
   1130  promise.setFixedSlot(PromiseSlot_Flags, Int32Value(flags | flag));
   1131 }
   1132 
   1133 static void RemovePromiseFlags(PromiseObject& promise, int32_t flag) {
   1134  int32_t flags = promise.flags();
   1135  promise.setFixedSlot(PromiseSlot_Flags, Int32Value(flags & ~flag));
   1136 }
   1137 
   1138 static bool PromiseHasAnyFlag(PromiseObject& promise, int32_t flag) {
   1139  return promise.flags() & flag;
   1140 }
   1141 
   1142 static bool ResolvePromiseFunction(JSContext* cx, unsigned argc, Value* vp);
   1143 static bool RejectPromiseFunction(JSContext* cx, unsigned argc, Value* vp);
   1144 
   1145 static JSFunction* GetResolveFunctionFromReject(JSFunction* reject);
   1146 static JSFunction* GetRejectFunctionFromResolve(JSFunction* resolve);
   1147 
   1148 #ifdef DEBUG
   1149 
   1150 /**
   1151 * Returns Promise Resolve Function's [[AlreadyResolved]].[[Value]].
   1152 */
   1153 static bool IsAlreadyResolvedResolveFunction(JSFunction* resolveFun) {
   1154  MOZ_ASSERT(resolveFun->maybeNative() == ResolvePromiseFunction);
   1155 
   1156  bool alreadyResolved =
   1157      resolveFun->getExtendedSlot(ResolveFunctionSlot_Promise).isUndefined();
   1158 
   1159  // Other slots should agree.
   1160  if (alreadyResolved) {
   1161    MOZ_ASSERT(resolveFun->getExtendedSlot(ResolveFunctionSlot_RejectFunction)
   1162                   .isUndefined());
   1163  } else {
   1164    JSFunction* rejectFun = GetRejectFunctionFromResolve(resolveFun);
   1165    MOZ_ASSERT(
   1166        !rejectFun->getExtendedSlot(RejectFunctionSlot_Promise).isUndefined());
   1167    MOZ_ASSERT(!rejectFun->getExtendedSlot(RejectFunctionSlot_ResolveFunction)
   1168                    .isUndefined());
   1169  }
   1170 
   1171  return alreadyResolved;
   1172 }
   1173 
   1174 /**
   1175 * Returns Promise Reject Function's [[AlreadyResolved]].[[Value]].
   1176 */
   1177 static bool IsAlreadyResolvedRejectFunction(JSFunction* rejectFun) {
   1178  MOZ_ASSERT(rejectFun->maybeNative() == RejectPromiseFunction);
   1179 
   1180  bool alreadyResolved =
   1181      rejectFun->getExtendedSlot(RejectFunctionSlot_Promise).isUndefined();
   1182 
   1183  // Other slots should agree.
   1184  if (alreadyResolved) {
   1185    MOZ_ASSERT(rejectFun->getExtendedSlot(RejectFunctionSlot_ResolveFunction)
   1186                   .isUndefined());
   1187  } else {
   1188    JSFunction* resolveFun = GetResolveFunctionFromReject(rejectFun);
   1189    MOZ_ASSERT(!resolveFun->getExtendedSlot(ResolveFunctionSlot_Promise)
   1190                    .isUndefined());
   1191    MOZ_ASSERT(!resolveFun->getExtendedSlot(ResolveFunctionSlot_RejectFunction)
   1192                    .isUndefined());
   1193  }
   1194 
   1195  return alreadyResolved;
   1196 }
   1197 
   1198 #endif  // DEBUG
   1199 
   1200 /**
   1201 * Set Promise Resolve Function's and Promise Reject Function's
   1202 * [[AlreadyResolved]].[[Value]] to true.
   1203 *
   1204 * `resolutionFun` can be either of them.
   1205 */
   1206 static void SetAlreadyResolvedResolutionFunction(JSFunction* resolutionFun) {
   1207  JSFunction* resolve;
   1208  JSFunction* reject;
   1209  if (resolutionFun->maybeNative() == ResolvePromiseFunction) {
   1210    resolve = resolutionFun;
   1211    reject = GetRejectFunctionFromResolve(resolutionFun);
   1212  } else {
   1213    resolve = GetResolveFunctionFromReject(resolutionFun);
   1214    reject = resolutionFun;
   1215  }
   1216 
   1217  resolve->setExtendedSlot(ResolveFunctionSlot_Promise, UndefinedValue());
   1218  resolve->setExtendedSlot(ResolveFunctionSlot_RejectFunction,
   1219                           UndefinedValue());
   1220 
   1221  reject->setExtendedSlot(RejectFunctionSlot_Promise, UndefinedValue());
   1222  reject->setExtendedSlot(RejectFunctionSlot_ResolveFunction, UndefinedValue());
   1223 
   1224  MOZ_ASSERT(IsAlreadyResolvedResolveFunction(resolve));
   1225  MOZ_ASSERT(IsAlreadyResolvedRejectFunction(reject));
   1226 }
   1227 
   1228 /**
   1229 * Returns true if given promise is created by
   1230 * CreatePromiseObjectWithoutResolutionFunctions.
   1231 */
   1232 bool js::IsPromiseWithDefaultResolvingFunction(PromiseObject* promise) {
   1233  return PromiseHasAnyFlag(*promise, PROMISE_FLAG_DEFAULT_RESOLVING_FUNCTIONS);
   1234 }
   1235 
   1236 /**
   1237 * Returns Promise Resolve Function's [[AlreadyResolved]].[[Value]] for
   1238 * a promise created by CreatePromiseObjectWithoutResolutionFunctions.
   1239 */
   1240 static bool IsAlreadyResolvedPromiseWithDefaultResolvingFunction(
   1241    PromiseObject* promise) {
   1242  MOZ_ASSERT(IsPromiseWithDefaultResolvingFunction(promise));
   1243 
   1244  if (promise->as<PromiseObject>().state() != JS::PromiseState::Pending) {
   1245    MOZ_ASSERT(PromiseHasAnyFlag(
   1246        *promise, PROMISE_FLAG_DEFAULT_RESOLVING_FUNCTIONS_ALREADY_RESOLVED));
   1247    return true;
   1248  }
   1249 
   1250  return PromiseHasAnyFlag(
   1251      *promise, PROMISE_FLAG_DEFAULT_RESOLVING_FUNCTIONS_ALREADY_RESOLVED);
   1252 }
   1253 
   1254 /**
   1255 * Set Promise Resolve Function's [[AlreadyResolved]].[[Value]] to true for
   1256 * a promise created by CreatePromiseObjectWithoutResolutionFunctions.
   1257 */
   1258 void js::SetAlreadyResolvedPromiseWithDefaultResolvingFunction(
   1259    PromiseObject* promise) {
   1260  MOZ_ASSERT(IsPromiseWithDefaultResolvingFunction(promise));
   1261 
   1262  promise->setFixedSlot(
   1263      PromiseSlot_Flags,
   1264      JS::Int32Value(
   1265          promise->flags() |
   1266          PROMISE_FLAG_DEFAULT_RESOLVING_FUNCTIONS_ALREADY_RESOLVED));
   1267 }
   1268 
   1269 /**
   1270 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   1271 *
   1272 * CreateResolvingFunctions ( promise )
   1273 * https://tc39.es/ecma262/#sec-createresolvingfunctions
   1274 */
   1275 [[nodiscard]] static MOZ_ALWAYS_INLINE bool CreateResolvingFunctions(
   1276    JSContext* cx, HandleObject promise, MutableHandleObject resolveFn,
   1277    MutableHandleObject rejectFn) {
   1278  // Step 1. Let alreadyResolved be the Record { [[Value]]: false }.
   1279  // (implicit, see steps 5-6, 10-11 below)
   1280 
   1281  // Step 2. Let stepsResolve be the algorithm steps defined in Promise Resolve
   1282  //         Functions.
   1283  // Step 3. Let lengthResolve be the number of non-optional parameters of the
   1284  //         function definition in Promise Resolve Functions.
   1285  // Step 4. Let resolve be
   1286  //         ! CreateBuiltinFunction(stepsResolve, lengthResolve, "",
   1287  //                                 « [[Promise]], [[AlreadyResolved]] »).
   1288  Handle<PropertyName*> funName = cx->names().empty_;
   1289  resolveFn.set(NewNativeFunction(cx, ResolvePromiseFunction, 1, funName,
   1290                                  gc::AllocKind::FUNCTION_EXTENDED,
   1291                                  GenericObject));
   1292  if (!resolveFn) {
   1293    return false;
   1294  }
   1295 
   1296  // Step 7. Let stepsReject be the algorithm steps defined in Promise Reject
   1297  //         Functions.
   1298  // Step 8. Let lengthReject be the number of non-optional parameters of the
   1299  //         function definition in Promise Reject Functions.
   1300  // Step 9. Let reject be
   1301  //         ! CreateBuiltinFunction(stepsReject, lengthReject, "",
   1302  //                                 « [[Promise]], [[AlreadyResolved]] »).
   1303  rejectFn.set(NewNativeFunction(cx, RejectPromiseFunction, 1, funName,
   1304                                 gc::AllocKind::FUNCTION_EXTENDED,
   1305                                 GenericObject));
   1306  if (!rejectFn) {
   1307    return false;
   1308  }
   1309 
   1310  JSFunction* resolveFun = &resolveFn->as<JSFunction>();
   1311  JSFunction* rejectFun = &rejectFn->as<JSFunction>();
   1312 
   1313  // Step 5. Set resolve.[[Promise]] to promise.
   1314  // Step 6. Set resolve.[[AlreadyResolved]] to alreadyResolved.
   1315  //
   1316  // NOTE: We use these references as [[AlreadyResolved]].[[Value]].
   1317  //       See the comment in ResolveFunctionSlots for more details.
   1318  resolveFun->initExtendedSlot(ResolveFunctionSlot_Promise,
   1319                               ObjectValue(*promise));
   1320  resolveFun->initExtendedSlot(ResolveFunctionSlot_RejectFunction,
   1321                               ObjectValue(*rejectFun));
   1322 
   1323  // Step 10. Set reject.[[Promise]] to promise.
   1324  // Step 11. Set reject.[[AlreadyResolved]] to alreadyResolved.
   1325  //
   1326  // NOTE: We use these references as [[AlreadyResolved]].[[Value]].
   1327  //       See the comment in ResolveFunctionSlots for more details.
   1328  rejectFun->initExtendedSlot(RejectFunctionSlot_Promise,
   1329                              ObjectValue(*promise));
   1330  rejectFun->initExtendedSlot(RejectFunctionSlot_ResolveFunction,
   1331                              ObjectValue(*resolveFun));
   1332 
   1333  MOZ_ASSERT(!IsAlreadyResolvedResolveFunction(resolveFun));
   1334  MOZ_ASSERT(!IsAlreadyResolvedRejectFunction(rejectFun));
   1335 
   1336  // Step 12. Return the Record { [[Resolve]]: resolve, [[Reject]]: reject }.
   1337  return true;
   1338 }
   1339 
   1340 static bool IsSettledMaybeWrappedPromise(JSObject* promise) {
   1341  if (IsProxy(promise)) {
   1342    promise = UncheckedUnwrap(promise);
   1343 
   1344    // Caller needs to handle dead wrappers.
   1345    if (JS_IsDeadWrapper(promise)) {
   1346      return false;
   1347    }
   1348  }
   1349 
   1350  return promise->as<PromiseObject>().state() != JS::PromiseState::Pending;
   1351 }
   1352 
   1353 [[nodiscard]] static bool RejectMaybeWrappedPromise(
   1354    JSContext* cx, HandleObject promiseObj, HandleValue reason,
   1355    Handle<SavedFrame*> unwrappedRejectionStack);
   1356 
   1357 /**
   1358 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   1359 *
   1360 * Promise Reject Functions
   1361 * https://tc39.es/ecma262/#sec-promise-reject-functions
   1362 */
   1363 static bool RejectPromiseFunction(JSContext* cx, unsigned argc, Value* vp) {
   1364  CallArgs args = CallArgsFromVp(argc, vp);
   1365 
   1366  JSFunction* reject = &args.callee().as<JSFunction>();
   1367  HandleValue reasonVal = args.get(0);
   1368 
   1369  // Step 1. Let F be the active function object.
   1370  // Step 2. Assert: F has a [[Promise]] internal slot whose value is an Object.
   1371  // (implicit)
   1372 
   1373  // Step 3. Let promise be F.[[Promise]].
   1374  const Value& promiseVal = reject->getExtendedSlot(RejectFunctionSlot_Promise);
   1375 
   1376  // Step 4. Let alreadyResolved be F.[[AlreadyResolved]].
   1377  // Step 5. If alreadyResolved.[[Value]] is true, return undefined.
   1378  //
   1379  // If the Promise isn't available anymore, it has been resolved and the
   1380  // reference to it removed to make it eligible for collection.
   1381  bool alreadyResolved = promiseVal.isUndefined();
   1382  MOZ_ASSERT(IsAlreadyResolvedRejectFunction(reject) == alreadyResolved);
   1383  if (alreadyResolved) {
   1384    args.rval().setUndefined();
   1385    return true;
   1386  }
   1387 
   1388  RootedObject promise(cx, &promiseVal.toObject());
   1389 
   1390  // Step 6. Set alreadyResolved.[[Value]] to true.
   1391  SetAlreadyResolvedResolutionFunction(reject);
   1392 
   1393  // In some cases the Promise reference on the resolution function won't
   1394  // have been removed during resolution, so we need to check that here,
   1395  // too.
   1396  if (IsSettledMaybeWrappedPromise(promise)) {
   1397    args.rval().setUndefined();
   1398    return true;
   1399  }
   1400 
   1401  // Step 7. Return RejectPromise(promise, reason).
   1402  if (!RejectMaybeWrappedPromise(cx, promise, reasonVal, nullptr)) {
   1403    return false;
   1404  }
   1405  args.rval().setUndefined();
   1406  return true;
   1407 }
   1408 
   1409 [[nodiscard]] static bool FulfillMaybeWrappedPromise(JSContext* cx,
   1410                                                     HandleObject promiseObj,
   1411                                                     HandleValue value_);
   1412 
   1413 [[nodiscard]] static bool EnqueuePromiseResolveThenableJob(
   1414    JSContext* cx, HandleValue promiseToResolve, HandleValue thenable,
   1415    HandleValue thenVal);
   1416 
   1417 [[nodiscard]] static bool EnqueuePromiseResolveThenableBuiltinJob(
   1418    JSContext* cx, HandleObject promiseToResolve, HandleObject thenable);
   1419 
   1420 static bool Promise_then_impl(JSContext* cx, HandleValue promiseVal,
   1421                              HandleValue onFulfilled, HandleValue onRejected,
   1422                              MutableHandleValue rval, bool rvalExplicitlyUsed);
   1423 
   1424 // This is used to get the 'then' property off of an object, and report some
   1425 // information back for telemetry purposes. When we no longer need this
   1426 // telemetry this function can be removed and replaced with GetProperty
   1427 bool GetThenValue(JSContext* cx, JS::Handle<JSObject*> obj,
   1428                  JS::Handle<JS::Value> reciever,
   1429                  JS::MutableHandle<Value> thenVal, bool* isOnProto,
   1430                  bool* isOnStandardProto, bool* isOnObjectProto) {
   1431  MOZ_ASSERT(isOnProto && *isOnProto == false);
   1432  MOZ_ASSERT(isOnStandardProto && *isOnStandardProto == false);
   1433  MOZ_ASSERT(isOnObjectProto && *isOnObjectProto == false);
   1434 
   1435  NativeObject* holder;
   1436  PropertyResult prop;
   1437 
   1438  // LookupProperty would be observable unforunately. If we can do the lookup,
   1439  // then we can produce information, but otherwise we're left blind.
   1440  // Fortunately, since this is purely for the purposes of telemetry, let's just
   1441  // use Pure.
   1442  RootedId thenId(cx, NameToId(cx->names().then));
   1443 
   1444  // If we're doing the lookup on the original promise prototype we want to only
   1445  // report telemetry if the value is not the original Promise.prototype.then
   1446  //
   1447  // We then need to defer until after the lookup to decide this.
   1448  bool maybeOnPromiseProto = false;
   1449  do {
   1450    if (LookupPropertyPure(cx, obj, thenId, &holder, &prop)) {
   1451      if (prop.isNotFound()) {
   1452        break;
   1453      }
   1454 
   1455      if (holder != obj) {
   1456        *isOnProto = true;
   1457 
   1458        auto key = JS::IdentifyStandardPrototype(holder);
   1459        if (key != JSProto_Null) {
   1460          if (key == JSProto_Promise) {
   1461            maybeOnPromiseProto = true;
   1462          } else {
   1463            *isOnStandardProto = true;
   1464            if (key == JSProto_Object) {
   1465              *isOnObjectProto = true;
   1466            }
   1467          }
   1468        }
   1469      }
   1470    }
   1471  } while (false);
   1472 
   1473  if (!GetProperty(cx, obj, reciever, cx->names().then, thenVal)) {
   1474    return false;
   1475  }
   1476 
   1477  if (maybeOnPromiseProto) {
   1478    *isOnStandardProto = !IsNativeFunction(thenVal, Promise_then);
   1479  }
   1480 
   1481  return true;
   1482 }
   1483 
   1484 void ReportThenable(JSContext* cx, bool isOnProto, bool isOnStandardProto,
   1485                    bool isOnObjectProto) {
   1486  cx->runtime()->setUseCounter(cx->global(), JSUseCounter::THENABLE_USE);
   1487 
   1488  if (isOnProto) {
   1489    cx->runtime()->setUseCounter(cx->global(),
   1490                                 JSUseCounter::THENABLE_USE_PROTO);
   1491    JS_LOG(thenable, Debug, "Thenable on proto");
   1492  }
   1493 
   1494  if (isOnStandardProto) {
   1495    cx->runtime()->setUseCounter(cx->global(),
   1496                                 JSUseCounter::THENABLE_USE_STANDARD_PROTO);
   1497    JS_LOG(thenable, Info, "Thenable on standard proto");
   1498  }
   1499 
   1500  if (isOnObjectProto) {
   1501    cx->runtime()->setUseCounter(cx->global(),
   1502                                 JSUseCounter::THENABLE_USE_OBJECT_PROTO);
   1503    JS_LOG(thenable, Info, "Thenable on Object.prototype");
   1504  }
   1505 }
   1506 
   1507 /**
   1508 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   1509 *
   1510 * Promise Resolve Functions
   1511 * https://tc39.es/ecma262/#sec-promise-resolve-functions
   1512 *
   1513 * Steps 7-15.
   1514 */
   1515 [[nodiscard]] bool js::ResolvePromiseInternal(
   1516    JSContext* cx, JS::Handle<JSObject*> promise,
   1517    JS::Handle<JS::Value> resolutionVal) {
   1518  cx->check(promise, resolutionVal);
   1519  MOZ_ASSERT(!IsSettledMaybeWrappedPromise(promise));
   1520 
   1521  // (reordered)
   1522  // Step 8. If Type(resolution) is not Object, then
   1523  if (!resolutionVal.isObject()) {
   1524    // Step 8.a. Return FulfillPromise(promise, resolution).
   1525    return FulfillMaybeWrappedPromise(cx, promise, resolutionVal);
   1526  }
   1527 
   1528  RootedObject resolution(cx, &resolutionVal.toObject());
   1529 
   1530  // Step 7. If SameValue(resolution, promise) is true, then
   1531  if (resolution == promise) {
   1532    // Step 7.a. Let selfResolutionError be a newly created TypeError object.
   1533    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   1534                              JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF);
   1535    RootedValue selfResolutionError(cx);
   1536    Rooted<SavedFrame*> stack(cx);
   1537    if (!MaybeGetAndClearExceptionAndStack(cx, &selfResolutionError, &stack)) {
   1538      return false;
   1539    }
   1540 
   1541    // Step 7.b. Return RejectPromise(promise, selfResolutionError).
   1542    return RejectMaybeWrappedPromise(cx, promise, selfResolutionError, stack);
   1543  }
   1544 
   1545  // Step 9. Let then be Get(resolution, "then").
   1546  RootedValue thenVal(cx);
   1547  bool isOnProto = false;
   1548  bool isOnStandardProto = false;
   1549  bool isOnObjectProto = false;
   1550  bool status = GetThenValue(cx, resolution, resolutionVal, &thenVal,
   1551                             &isOnProto, &isOnStandardProto, &isOnObjectProto);
   1552 
   1553  RootedValue error(cx);
   1554  Rooted<SavedFrame*> errorStack(cx);
   1555 
   1556  // Step 10. If then is an abrupt completion, then
   1557  if (!status) {
   1558    // Get the `then.[[Value]]` value used in the step 10.a.
   1559    if (!MaybeGetAndClearExceptionAndStack(cx, &error, &errorStack)) {
   1560      return false;
   1561    }
   1562  }
   1563 
   1564  // Testing functions allow to directly settle a promise without going
   1565  // through the resolving functions. In that case the normal bookkeeping to
   1566  // ensure only pending promises can be resolved doesn't apply and we need
   1567  // to manually check for already settled promises. The exception is simply
   1568  // dropped when this case happens.
   1569  if (IsSettledMaybeWrappedPromise(promise)) {
   1570    return true;
   1571  }
   1572 
   1573  // Step 10. If then is an abrupt completion, then
   1574  if (!status) {
   1575    // Step 10.a. Return RejectPromise(promise, then.[[Value]]).
   1576    return RejectMaybeWrappedPromise(cx, promise, error, errorStack);
   1577  }
   1578 
   1579  // Step 11. Let thenAction be then.[[Value]].
   1580  // (implicit)
   1581 
   1582  // Step 12. If IsCallable(thenAction) is false, then
   1583  if (!IsCallable(thenVal)) {
   1584    // Step 12.a. Return FulfillPromise(promise, resolution).
   1585    return FulfillMaybeWrappedPromise(cx, promise, resolutionVal);
   1586  }
   1587 
   1588  // Step 13. Let thenJobCallback be HostMakeJobCallback(thenAction).
   1589  // (implicit)
   1590 
   1591  // Step 14. Let job be
   1592  //          NewPromiseResolveThenableJob(promise, resolution,
   1593  //                                       thenJobCallback).
   1594  // Step 15. Perform HostEnqueuePromiseJob(job.[[Job]], job.[[Realm]]).
   1595 
   1596  // If the resolution object is a built-in Promise object and the
   1597  // `then` property is the original Promise.prototype.then function
   1598  // from the current realm, we skip storing/calling it.
   1599  // Additionally we require that |promise| itself is also a built-in
   1600  // Promise object, so the fast path doesn't need to cope with wrappers.
   1601  bool isBuiltinThen = false;
   1602  if (resolution->is<PromiseObject>() && promise->is<PromiseObject>() &&
   1603      IsNativeFunction(thenVal, Promise_then) &&
   1604      thenVal.toObject().as<JSFunction>().realm() == cx->realm()) {
   1605    isBuiltinThen = true;
   1606  }
   1607 
   1608  if (!isBuiltinThen) {
   1609    ReportThenable(cx, isOnProto, isOnStandardProto, isOnObjectProto);
   1610 
   1611    RootedValue promiseVal(cx, ObjectValue(*promise));
   1612    if (!EnqueuePromiseResolveThenableJob(cx, promiseVal, resolutionVal,
   1613                                          thenVal)) {
   1614      return false;
   1615    }
   1616  } else {
   1617    if (!EnqueuePromiseResolveThenableBuiltinJob(cx, promise, resolution)) {
   1618      return false;
   1619    }
   1620  }
   1621 
   1622  return true;
   1623 }
   1624 
   1625 /**
   1626 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   1627 *
   1628 * Promise Resolve Functions
   1629 * https://tc39.es/ecma262/#sec-promise-resolve-functions
   1630 */
   1631 static bool ResolvePromiseFunction(JSContext* cx, unsigned argc, Value* vp) {
   1632  CallArgs args = CallArgsFromVp(argc, vp);
   1633 
   1634  // Step 1. Let F be the active function object.
   1635  // Step 2. Assert: F has a [[Promise]] internal slot whose value is an Object.
   1636  // (implicit)
   1637 
   1638  JSFunction* resolve = &args.callee().as<JSFunction>();
   1639  HandleValue resolutionVal = args.get(0);
   1640 
   1641  // Step 3. Let promise be F.[[Promise]].
   1642  const Value& promiseVal =
   1643      resolve->getExtendedSlot(ResolveFunctionSlot_Promise);
   1644 
   1645  // Step 4. Let alreadyResolved be F.[[AlreadyResolved]].
   1646  // Step 5. If alreadyResolved.[[Value]] is true, return undefined.
   1647  //
   1648  // NOTE: We use the reference to the reject function as [[AlreadyResolved]].
   1649  bool alreadyResolved = promiseVal.isUndefined();
   1650  MOZ_ASSERT(IsAlreadyResolvedResolveFunction(resolve) == alreadyResolved);
   1651  if (alreadyResolved) {
   1652    args.rval().setUndefined();
   1653    return true;
   1654  }
   1655 
   1656  RootedObject promise(cx, &promiseVal.toObject());
   1657 
   1658  // Step 6. Set alreadyResolved.[[Value]] to true.
   1659  SetAlreadyResolvedResolutionFunction(resolve);
   1660 
   1661  // In some cases the Promise reference on the resolution function won't
   1662  // have been removed during resolution, so we need to check that here,
   1663  // too.
   1664  if (IsSettledMaybeWrappedPromise(promise)) {
   1665    args.rval().setUndefined();
   1666    return true;
   1667  }
   1668 
   1669  // Steps 7-15.
   1670  if (!ResolvePromiseInternal(cx, promise, resolutionVal)) {
   1671    return false;
   1672  }
   1673 
   1674  // Step 16. Return undefined.
   1675  args.rval().setUndefined();
   1676  return true;
   1677 }
   1678 
   1679 static bool EnqueueJob(JSContext* cx, JS::JSMicroTask* job) {
   1680  MOZ_ASSERT(cx->realm());
   1681  GeckoProfilerRuntime& profiler = cx->runtime()->geckoProfiler();
   1682  if (profiler.enabled()) {
   1683    // Emit a flow start marker here.
   1684    uint64_t uid = 0;
   1685    if (JS::GetFlowIdFromJSMicroTask(job, &uid)) {
   1686      profiler.markFlow("JS::EnqueueJob", uid,
   1687                        JS::ProfilingCategoryPair::OTHER);
   1688    }
   1689  }
   1690 
   1691  // We need to root this job because useDebugQueue can GC.
   1692  Rooted<JS::JSMicroTask*> rootedJob(cx, job);
   1693 
   1694  // Only check if we need to use the debug queue when we're not on main thread.
   1695  if (MOZ_UNLIKELY(!cx->runtime()->isMainRuntime() &&
   1696                   cx->jobQueue->useDebugQueue(cx->global()))) {
   1697    return cx->microTaskQueues->enqueueDebugMicroTask(cx,
   1698                                                      ObjectValue(*rootedJob));
   1699  }
   1700  return cx->microTaskQueues->enqueueRegularMicroTask(cx,
   1701                                                      ObjectValue(*rootedJob));
   1702 }
   1703 
   1704 static bool PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp);
   1705 
   1706 /**
   1707 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   1708 *
   1709 * NewPromiseReactionJob ( reaction, argument )
   1710 * https://tc39.es/ecma262/#sec-newpromisereactionjob
   1711 * HostEnqueuePromiseJob ( job, realm )
   1712 * https://tc39.es/ecma262/#sec-hostenqueuepromisejob
   1713 *
   1714 * Tells the embedding to enqueue a Promise reaction job, based on
   1715 * three parameters:
   1716 * reactionObj - The reaction record.
   1717 * handlerArg_ - The first and only argument to pass to the handler invoked by
   1718 *              the job. This will be stored on the reaction record.
   1719 * targetState - The PromiseState this reaction job targets. This decides
   1720 *               whether the onFulfilled or onRejected handler is called.
   1721 */
   1722 [[nodiscard]] static bool EnqueuePromiseReactionJob(
   1723    JSContext* cx, HandleObject reactionObj, HandleValue handlerArg_,
   1724    JS::PromiseState targetState) {
   1725  MOZ_ASSERT(targetState == JS::PromiseState::Fulfilled ||
   1726             targetState == JS::PromiseState::Rejected);
   1727 
   1728  // The reaction might have been stored on a Promise from another
   1729  // compartment, which means it would've been wrapped in a CCW.
   1730  // To properly handle that case here, unwrap it and enter its
   1731  // compartment, where the job creation should take place anyway.
   1732  RootedTuple<PromiseReactionRecord*, Value, Value, Value, JSObject*,
   1733              JSFunction*, JSObject*, JSObject*>
   1734      roots(cx);
   1735  RootedField<PromiseReactionRecord*, 0> reaction(roots);
   1736  RootedField<Value, 1> handlerArg(roots, handlerArg_);
   1737  mozilla::Maybe<AutoRealm> ar;
   1738  if (!IsProxy(reactionObj)) {
   1739    MOZ_RELEASE_ASSERT(reactionObj->is<PromiseReactionRecord>());
   1740    reaction = &reactionObj->as<PromiseReactionRecord>();
   1741    if (cx->realm() != reaction->realm()) {
   1742      // If the compartment has multiple realms, create the job in the
   1743      // reaction's realm. This is consistent with the code in the else-branch
   1744      // and avoids problems with running jobs against a dying global (Gecko
   1745      // drops such jobs).
   1746      ar.emplace(cx, reaction);
   1747    }
   1748  } else {
   1749    JSObject* unwrappedReactionObj = UncheckedUnwrap(reactionObj);
   1750    if (JS_IsDeadWrapper(unwrappedReactionObj)) {
   1751      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   1752                                JSMSG_DEAD_OBJECT);
   1753      return false;
   1754    }
   1755    reaction = &unwrappedReactionObj->as<PromiseReactionRecord>();
   1756    MOZ_RELEASE_ASSERT(reaction->is<PromiseReactionRecord>());
   1757    ar.emplace(cx, reaction);
   1758    if (!cx->compartment()->wrap(cx, &handlerArg)) {
   1759      return false;
   1760    }
   1761  }
   1762 
   1763  // Must not enqueue a reaction job more than once.
   1764  MOZ_ASSERT(reaction->targetState() == JS::PromiseState::Pending);
   1765 
   1766  // NOTE: Instead of capturing reaction and arguments separately in the
   1767  //       Job Abstract Closure below, store arguments (= handlerArg) in
   1768  //       reaction object and capture it.
   1769  //       Also, set reaction.[[Type]] is represented by targetState here.
   1770  cx->check(handlerArg);
   1771  reaction->setTargetStateAndHandlerArg(targetState, handlerArg);
   1772 
   1773  RootedField<Value, 2> reactionVal(roots, ObjectValue(*reaction));
   1774  RootedField<Value, 3> handler(roots, reaction->handler());
   1775 
   1776  // NewPromiseReactionJob
   1777  // Step 2. Let handlerRealm be null.
   1778  // NOTE: Instead of passing job and realm separately, we use the job's
   1779  //       JSFunction object's realm as the job's realm.
   1780  //       So we should enter the handlerRealm before creating the job function.
   1781  //
   1782  // GetFunctionRealm performed inside AutoFunctionOrCurrentRealm uses checked
   1783  // unwrap and it can hit permission error if there's a security wrapper, and
   1784  // in that case the reaction job is created in the current realm, instead of
   1785  // the target function's realm.
   1786  //
   1787  // If this reaction crosses chrome/content boundary, and the security
   1788  // wrapper would allow "call" operation, it still works inside the
   1789  // reaction job.
   1790  //
   1791  // This behavior is observable only when the job belonging to the content
   1792  // realm stops working (*1, *2), and it won't matter in practice.
   1793  //
   1794  // *1: "we can run script" performed inside HostEnqueuePromiseJob
   1795  //     in HTML spec
   1796  //       https://html.spec.whatwg.org/#hostenqueuepromisejob
   1797  //       https://html.spec.whatwg.org/#check-if-we-can-run-script
   1798  //       https://html.spec.whatwg.org/#fully-active
   1799  // *2: nsIGlobalObject::IsDying performed inside PromiseJobRunnable::Run
   1800  //     in our implementation
   1801  mozilla::Maybe<AutoFunctionOrCurrentRealm> ar2;
   1802 
   1803  // NewPromiseReactionJob
   1804  // Step 3. If reaction.[[Handler]] is not empty, then
   1805  if (handler.isObject()) {
   1806    // Step 3.a. Let getHandlerRealmResult be
   1807    //           GetFunctionRealm(reaction.[[Handler]].[[Callback]]).
   1808    // Step 3.b. If getHandlerRealmResult is a normal completion,
   1809    //           set handlerRealm to getHandlerRealmResult.[[Value]].
   1810    // Step 3.c. Else, set handlerRealm to the current Realm Record.
   1811    // Step 3.d. NOTE: handlerRealm is never null unless the handler is
   1812    //           undefined. When the handler is a revoked Proxy and no
   1813    //           ECMAScript code runs, handlerRealm is used to create error
   1814    //           objects.
   1815    RootedField<JSObject*, 4> handlerObj(roots, &handler.toObject());
   1816    ar2.emplace(cx, handlerObj);
   1817 
   1818    // This is wrapped here because it may be a cross comaprtment
   1819    // reference, and so should be wrapped to be stored on the job function.
   1820    // (it's also important because this indicates to PromiseReactionJob
   1821    // that it needs to switch realms).
   1822    if (!cx->compartment()->wrap(cx, &reactionVal)) {
   1823      return false;
   1824    }
   1825  }
   1826 
   1827  // When using JS::AddPromiseReactions{,IgnoringUnHandledRejection}, no actual
   1828  // promise is created, so we might not have one here.
   1829  //
   1830  // Bug 1977691: This comment needs updating; I don't think
   1831  // JS::AddPromiseReactions happens without a promise anymore, _however_ async
   1832  // functions may not have a promise.
   1833  //
   1834  //
   1835  // Additionally, we might have an object here that isn't an instance of
   1836  // Promise. This can happen if content overrides the value of
   1837  // Promise[@@species] (or invokes Promise#then on a Promise subclass
   1838  // instance with a non-default @@species value on the constructor) with a
   1839  // function that returns objects that're not Promise (subclass) instances.
   1840  // In that case, we just pretend we didn't have an object in the first
   1841  // place.
   1842  // If after all this we do have an object, wrap it in case we entered the
   1843  // handler's compartment above, because we should pass objects from a
   1844  // single compartment to the enqueuePromiseJob callback.
   1845  RootedField<JSObject*, 6> promise(roots, reaction->promise());
   1846  if (promise) {
   1847    if (promise->is<PromiseObject>()) {
   1848      if (!cx->compartment()->wrap(cx, &promise)) {
   1849        return false;
   1850      }
   1851    } else if (IsWrapper(promise)) {
   1852      // `promise` can be already-wrapped promise object at this point.
   1853      JSObject* unwrappedPromise = UncheckedUnwrap(promise);
   1854      if (unwrappedPromise->is<PromiseObject>()) {
   1855        if (!cx->compartment()->wrap(cx, &promise)) {
   1856          return false;
   1857        }
   1858      } else {
   1859        promise = nullptr;
   1860      }
   1861    } else {
   1862      promise = nullptr;
   1863    }
   1864  }
   1865 
   1866  // NewPromiseReactionJob
   1867  // Step 1 (reordered). Let job be a new Job Abstract Closure with no
   1868  //                     parameters that captures reaction and argument
   1869  //                     and performs the following steps when called:
   1870  if (JS::Prefs::use_js_microtask_queue()) {
   1871    MOZ_ASSERT(reactionVal.isObject());
   1872 
   1873    // Get a representative object for this global: We will use this later
   1874    // to extract the target global for execution. We don't store the global
   1875    // directly because CCWs to globals can change identity.
   1876    //
   1877    // So instead we simply store Object.prototype from the target global,
   1878    // an object which always exists.
   1879    RootedObject globalRepresentative(cx, &cx->global()->getObjectPrototype());
   1880 
   1881    // PromiseReactionJob job will use the existence of a CCW as a signal
   1882    // to change to the reactionVal's realm for execution. I believe
   1883    // this is the right thing to do. As a result however we don't actually
   1884    // need to track the global. We simply allow PromiseReactionJob to
   1885    // do the right thing. We will need to enqueue a CCW however
   1886    {
   1887      AutoRealm ar(cx, reaction);
   1888 
   1889      RootedObject stack(
   1890          cx,
   1891          JS::MaybeGetPromiseAllocationSiteFromPossiblyWrappedPromise(promise));
   1892      if (!cx->compartment()->wrap(cx, &stack)) {
   1893        return false;
   1894      }
   1895      reaction->setAllocationStack(stack);
   1896 
   1897      if (!reaction->getHostDefinedData().isObject()) {
   1898        // We do need to still provide an incumbentGlobal here
   1899        // MG:XXX: I'm pretty sure this can be appreciably more elegant later.
   1900        RootedObject hostGlobal(cx);
   1901        if (!cx->jobQueue->getHostDefinedGlobal(cx, &hostGlobal)) {
   1902          return false;
   1903        }
   1904 
   1905        if (hostGlobal) {
   1906          MOZ_ASSERT(hostGlobal->is<GlobalObject>());
   1907          // Recycle the root -- we store the prototype for the same
   1908          // reason as EnqueueGlobalRepresentative.
   1909          hostGlobal = &hostGlobal->as<GlobalObject>().getObjectPrototype();
   1910        }
   1911 
   1912        if (!cx->compartment()->wrap(cx, &hostGlobal)) {
   1913          return false;
   1914        }
   1915        reaction->setHostDefinedGlobalRepresentative(hostGlobal);
   1916      }
   1917 
   1918      if (!cx->compartment()->wrap(cx, &globalRepresentative)) {
   1919        return false;
   1920      }
   1921      reaction->setEnqueueGlobalRepresentative(globalRepresentative);
   1922    }
   1923 
   1924    if (!cx->compartment()->wrap(cx, &reactionVal)) {
   1925      return false;
   1926    }
   1927 
   1928    // HostEnqueuePromiseJob(job.[[Job]], job.[[Realm]]).
   1929    return EnqueueJob(cx, &reactionVal.toObject());
   1930  }
   1931 
   1932  RootedField<JSObject*, 7> hostDefinedData(roots);
   1933  if (JSObject* hostDefined = reaction->getAndClearHostDefinedData()) {
   1934    hostDefined = CheckedUnwrapStatic(hostDefined);
   1935    MOZ_ASSERT(hostDefined);
   1936    // If the hostDefined object becomes a dead wrapper here, the target
   1937    // global has already gone, and the job queue won't run the promise job
   1938    // anyway.
   1939    if (JS_IsDeadWrapper(hostDefined)) {
   1940      return true;
   1941    }
   1942    hostDefinedData = hostDefined;
   1943  }
   1944 
   1945  Handle<PropertyName*> funName = cx->names().empty_;
   1946  RootedField<JSFunction*, 5> job(
   1947      roots,
   1948      NewNativeFunction(cx, PromiseReactionJob, 0, funName,
   1949                        gc::AllocKind::FUNCTION_EXTENDED, GenericObject));
   1950  if (!job) {
   1951    return false;
   1952  }
   1953 
   1954  job->setExtendedSlot(ReactionJobSlot_ReactionRecord, reactionVal);
   1955 
   1956  return cx->runtime()->enqueuePromiseJob(cx, job, promise, hostDefinedData);
   1957 }
   1958 
   1959 [[nodiscard]] static bool TriggerPromiseReactions(JSContext* cx,
   1960                                                  HandleValue reactionsVal,
   1961                                                  JS::PromiseState state,
   1962                                                  HandleValue valueOrReason);
   1963 
   1964 /**
   1965 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   1966 *
   1967 * FulfillPromise ( promise, value )
   1968 * https://tc39.es/ecma262/#sec-fulfillpromise
   1969 * RejectPromise ( promise, reason )
   1970 * https://tc39.es/ecma262/#sec-rejectpromise
   1971 *
   1972 * This method takes an additional optional |unwrappedRejectionStack| parameter,
   1973 * which is only used for debugging purposes.
   1974 * It allows callers to to pass in the stack of some exception which
   1975 * triggered the rejection of the promise.
   1976 */
   1977 [[nodiscard]] static bool ResolvePromise(
   1978    JSContext* cx, Handle<PromiseObject*> promise, HandleValue valueOrReason,
   1979    JS::PromiseState state,
   1980    Handle<SavedFrame*> unwrappedRejectionStack = nullptr) {
   1981  // Step 1. Assert: The value of promise.[[PromiseState]] is pending.
   1982  MOZ_ASSERT(promise->state() == JS::PromiseState::Pending);
   1983  MOZ_ASSERT(state == JS::PromiseState::Fulfilled ||
   1984             state == JS::PromiseState::Rejected);
   1985  MOZ_ASSERT_IF(unwrappedRejectionStack, state == JS::PromiseState::Rejected);
   1986 
   1987  // FulfillPromise
   1988  // Step 2. Let reactions be promise.[[PromiseFulfillReactions]].
   1989  // RejectPromise
   1990  // Step 2. Let reactions be promise.[[PromiseRejectReactions]].
   1991  //
   1992  // We only have one list of reactions for both resolution types. So
   1993  // instead of getting the right list of reactions, we determine the
   1994  // resolution type to retrieve the right information from the
   1995  // reaction records.
   1996  RootedValue reactionsVal(cx, promise->reactions());
   1997 
   1998  // FulfillPromise
   1999  // Step 3. Set promise.[[PromiseResult]] to value.
   2000  // RejectPromise
   2001  // Step 3. Set promise.[[PromiseResult]] to reason.
   2002  //
   2003  // Step 4. Set promise.[[PromiseFulfillReactions]] to undefined.
   2004  // Step 5. Set promise.[[PromiseRejectReactions]] to undefined.
   2005  //
   2006  // The same slot is used for the reactions list and the result, so setting
   2007  // the result also removes the reactions list.
   2008  promise->setFixedSlot(PromiseSlot_ReactionsOrResult, valueOrReason);
   2009 
   2010  // FulfillPromise
   2011  // Step 6. Set promise.[[PromiseState]] to fulfilled.
   2012  // RejectPromise
   2013  // Step 6. Set promise.[[PromiseState]] to rejected.
   2014  int32_t flags = promise->flags();
   2015  flags |= PROMISE_FLAG_RESOLVED;
   2016  if (state == JS::PromiseState::Fulfilled) {
   2017    flags |= PROMISE_FLAG_FULFILLED;
   2018  }
   2019  promise->setFixedSlot(PromiseSlot_Flags, Int32Value(flags));
   2020 
   2021  // Also null out the resolve/reject functions so they can be GC'd.
   2022  promise->setFixedSlot(PromiseSlot_RejectFunction, UndefinedValue());
   2023 
   2024  // Now that everything else is done, do the things the debugger needs.
   2025 
   2026  // RejectPromise
   2027  // Step 7. If promise.[[PromiseIsHandled]] is false, perform
   2028  //         HostPromiseRejectionTracker(promise, "reject").
   2029  PromiseObject::onSettled(cx, promise, unwrappedRejectionStack);
   2030 
   2031  // FulfillPromise
   2032  // Step 7. Return TriggerPromiseReactions(reactions, value).
   2033  // RejectPromise
   2034  // Step 8. Return TriggerPromiseReactions(reactions, reason).
   2035  return TriggerPromiseReactions(cx, reactionsVal, state, valueOrReason);
   2036 }
   2037 
   2038 /**
   2039 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   2040 *
   2041 * RejectPromise ( promise, reason )
   2042 * https://tc39.es/ecma262/#sec-rejectpromise
   2043 */
   2044 [[nodiscard]] bool js::RejectPromiseInternal(
   2045    JSContext* cx, JS::Handle<PromiseObject*> promise,
   2046    JS::Handle<JS::Value> reason,
   2047    JS::Handle<SavedFrame*> unwrappedRejectionStack /* = nullptr */) {
   2048  return ResolvePromise(cx, promise, reason, JS::PromiseState::Rejected,
   2049                        unwrappedRejectionStack);
   2050 }
   2051 
   2052 /**
   2053 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   2054 *
   2055 * FulfillPromise ( promise, value )
   2056 * https://tc39.es/ecma262/#sec-fulfillpromise
   2057 */
   2058 [[nodiscard]] static bool FulfillMaybeWrappedPromise(JSContext* cx,
   2059                                                     HandleObject promiseObj,
   2060                                                     HandleValue value_) {
   2061  Rooted<PromiseObject*> promise(cx);
   2062  RootedValue value(cx, value_);
   2063 
   2064  mozilla::Maybe<AutoRealm> ar;
   2065  if (!IsProxy(promiseObj)) {
   2066    promise = &promiseObj->as<PromiseObject>();
   2067  } else {
   2068    JSObject* unwrappedPromiseObj = UncheckedUnwrap(promiseObj);
   2069    if (JS_IsDeadWrapper(unwrappedPromiseObj)) {
   2070      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   2071                                JSMSG_DEAD_OBJECT);
   2072      return false;
   2073    }
   2074    promise = &unwrappedPromiseObj->as<PromiseObject>();
   2075    ar.emplace(cx, promise);
   2076    if (!cx->compartment()->wrap(cx, &value)) {
   2077      return false;
   2078    }
   2079  }
   2080 
   2081  return ResolvePromise(cx, promise, value, JS::PromiseState::Fulfilled);
   2082 }
   2083 
   2084 static bool GetCapabilitiesExecutor(JSContext* cx, unsigned argc, Value* vp);
   2085 static bool PromiseConstructor(JSContext* cx, unsigned argc, Value* vp);
   2086 [[nodiscard]] static PromiseObject* CreatePromiseObjectInternal(
   2087    JSContext* cx, HandleObject proto = nullptr, bool protoIsWrapped = false,
   2088    bool informDebugger = true);
   2089 
   2090 enum GetCapabilitiesExecutorSlots {
   2091  GetCapabilitiesExecutorSlots_Resolve,
   2092  GetCapabilitiesExecutorSlots_Reject
   2093 };
   2094 
   2095 /**
   2096 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   2097 *
   2098 * Promise ( executor )
   2099 * https://tc39.es/ecma262/#sec-promise-executor
   2100 */
   2101 [[nodiscard]] PromiseObject* js::CreatePromiseObjectWithoutResolutionFunctions(
   2102    JSContext* cx) {
   2103  // Steps 3-7.
   2104  PromiseObject* promise = CreatePromiseObjectInternal(cx);
   2105  if (!promise) {
   2106    return nullptr;
   2107  }
   2108 
   2109  AddPromiseFlags(*promise, PROMISE_FLAG_DEFAULT_RESOLVING_FUNCTIONS);
   2110 
   2111  // Step 11. Return promise.
   2112  return promise;
   2113 }
   2114 
   2115 /**
   2116 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   2117 *
   2118 * Promise ( executor )
   2119 * https://tc39.es/ecma262/#sec-promise-executor
   2120 *
   2121 * As if called with GetCapabilitiesExecutor as the executor argument.
   2122 */
   2123 [[nodiscard]] static PromiseObject* CreatePromiseWithDefaultResolutionFunctions(
   2124    JSContext* cx, MutableHandleObject resolve, MutableHandleObject reject) {
   2125  // Steps 3-7.
   2126  Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx));
   2127  if (!promise) {
   2128    return nullptr;
   2129  }
   2130 
   2131  // Step 8. Let resolvingFunctions be CreateResolvingFunctions(promise).
   2132  if (!CreateResolvingFunctions(cx, promise, resolve, reject)) {
   2133    return nullptr;
   2134  }
   2135 
   2136  promise->setFixedSlot(PromiseSlot_RejectFunction, ObjectValue(*reject));
   2137 
   2138  // Step 11. Return promise.
   2139  return promise;
   2140 }
   2141 
   2142 /**
   2143 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   2144 *
   2145 * NewPromiseCapability ( C )
   2146 * https://tc39.es/ecma262/#sec-newpromisecapability
   2147 */
   2148 [[nodiscard]] static bool NewPromiseCapability(
   2149    JSContext* cx, HandleObject C, MutableHandle<PromiseCapability> capability,
   2150    bool canOmitResolutionFunctions) {
   2151  RootedValue cVal(cx, ObjectValue(*C));
   2152 
   2153  // Step 1. If IsConstructor(C) is false, throw a TypeError exception.
   2154  // Step 2. NOTE: C is assumed to be a constructor function that supports the
   2155  // parameter conventions of the Promise constructor (see 27.2.3.1).
   2156  if (!IsConstructor(C)) {
   2157    ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_SEARCH_STACK, cVal,
   2158                     nullptr);
   2159    return false;
   2160  }
   2161 
   2162  // If we'd call the original Promise constructor and know that the
   2163  // resolve/reject functions won't ever escape to content, we can skip
   2164  // creating and calling the executor function and instead return a Promise
   2165  // marked as having default resolve/reject functions.
   2166  //
   2167  // This can't be used in Promise.all and Promise.race because we have to
   2168  // pass the reject (and resolve, in the race case) function to thenables
   2169  // in the list passed to all/race, which (potentially) means exposing them
   2170  // to content.
   2171  //
   2172  // For Promise.all and Promise.race we can only optimize away the creation
   2173  // of the GetCapabilitiesExecutor function, and directly allocate the
   2174  // result promise instead of invoking the Promise constructor.
   2175  if (IsNativeFunction(cVal, PromiseConstructor) &&
   2176      cVal.toObject().nonCCWRealm() == cx->realm()) {
   2177    PromiseObject* promise;
   2178    if (canOmitResolutionFunctions) {
   2179      promise = CreatePromiseObjectWithoutResolutionFunctions(cx);
   2180    } else {
   2181      promise = CreatePromiseWithDefaultResolutionFunctions(
   2182          cx, capability.resolve(), capability.reject());
   2183    }
   2184    if (!promise) {
   2185      return false;
   2186    }
   2187 
   2188    // Step 3. Let promiseCapability be the PromiseCapability Record
   2189    //         { [[Promise]]: undefined, [[Resolve]]: undefined,
   2190    //           [[Reject]]: undefined }.
   2191    capability.promise().set(promise);
   2192 
   2193    // Step 10. Return promiseCapability.
   2194    return true;
   2195  }
   2196 
   2197  // Step 4. Let executorClosure be a new Abstract Closure with parameters
   2198  //         (resolve, reject) that captures promiseCapability and performs the
   2199  //         following steps when called:
   2200  Handle<PropertyName*> funName = cx->names().empty_;
   2201  RootedFunction executor(
   2202      cx, NewNativeFunction(cx, GetCapabilitiesExecutor, 2, funName,
   2203                            gc::AllocKind::FUNCTION_EXTENDED, GenericObject));
   2204  if (!executor) {
   2205    return false;
   2206  }
   2207 
   2208  // Step 5. Let executor be
   2209  //         ! CreateBuiltinFunction(executorClosure, 2, "", « »).
   2210  // (omitted)
   2211 
   2212  // Step 6. Let promise be ? Construct(C, « executor »).
   2213  // Step 9. Set promiseCapability.[[Promise]] to promise.
   2214  FixedConstructArgs<1> cargs(cx);
   2215  cargs[0].setObject(*executor);
   2216  if (!Construct(cx, cVal, cargs, cVal, capability.promise())) {
   2217    return false;
   2218  }
   2219 
   2220  // Step 7. If IsCallable(promiseCapability.[[Resolve]]) is false,
   2221  //         throw a TypeError exception.
   2222  const Value& resolveVal =
   2223      executor->getExtendedSlot(GetCapabilitiesExecutorSlots_Resolve);
   2224  if (!IsCallable(resolveVal)) {
   2225    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   2226                              JSMSG_PROMISE_RESOLVE_FUNCTION_NOT_CALLABLE);
   2227    return false;
   2228  }
   2229 
   2230  // Step 8. If IsCallable(promiseCapability.[[Reject]]) is false,
   2231  //         throw a TypeError exception.
   2232  const Value& rejectVal =
   2233      executor->getExtendedSlot(GetCapabilitiesExecutorSlots_Reject);
   2234  if (!IsCallable(rejectVal)) {
   2235    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   2236                              JSMSG_PROMISE_REJECT_FUNCTION_NOT_CALLABLE);
   2237    return false;
   2238  }
   2239 
   2240  // (reordered)
   2241  // Step 3. Let promiseCapability be the PromiseCapability Record
   2242  //         { [[Promise]]: undefined, [[Resolve]]: undefined,
   2243  //           [[Reject]]: undefined }.
   2244  capability.resolve().set(&resolveVal.toObject());
   2245  capability.reject().set(&rejectVal.toObject());
   2246 
   2247  // Step 10. Return promiseCapability.
   2248  return true;
   2249 }
   2250 
   2251 /**
   2252 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   2253 *
   2254 * NewPromiseCapability ( C )
   2255 * https://tc39.es/ecma262/#sec-newpromisecapability
   2256 *
   2257 * Steps 4.a-e.
   2258 */
   2259 static bool GetCapabilitiesExecutor(JSContext* cx, unsigned argc, Value* vp) {
   2260  CallArgs args = CallArgsFromVp(argc, vp);
   2261  JSFunction* F = &args.callee().as<JSFunction>();
   2262 
   2263  // Step 4.a. If promiseCapability.[[Resolve]] is not undefined,
   2264  //           throw a TypeError exception.
   2265  // Step 4.b. If promiseCapability.[[Reject]] is not undefined,
   2266  //           throw a TypeError exception.
   2267  if (!F->getExtendedSlot(GetCapabilitiesExecutorSlots_Resolve).isUndefined() ||
   2268      !F->getExtendedSlot(GetCapabilitiesExecutorSlots_Reject).isUndefined()) {
   2269    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   2270                              JSMSG_PROMISE_CAPABILITY_HAS_SOMETHING_ALREADY);
   2271    return false;
   2272  }
   2273 
   2274  // Step 4.c. Set promiseCapability.[[Resolve]] to resolve.
   2275  F->setExtendedSlot(GetCapabilitiesExecutorSlots_Resolve, args.get(0));
   2276 
   2277  // Step 4.d. Set promiseCapability.[[Reject]] to reject.
   2278  F->setExtendedSlot(GetCapabilitiesExecutorSlots_Reject, args.get(1));
   2279 
   2280  // Step 4.e. Return undefined.
   2281  args.rval().setUndefined();
   2282  return true;
   2283 }
   2284 
   2285 /**
   2286 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   2287 *
   2288 * RejectPromise ( promise, reason )
   2289 * https://tc39.es/ecma262/#sec-rejectpromise
   2290 */
   2291 [[nodiscard]] static bool RejectMaybeWrappedPromise(
   2292    JSContext* cx, HandleObject promiseObj, HandleValue reason_,
   2293    Handle<SavedFrame*> unwrappedRejectionStack) {
   2294  Rooted<PromiseObject*> promise(cx);
   2295  RootedValue reason(cx, reason_);
   2296 
   2297  mozilla::Maybe<AutoRealm> ar;
   2298  if (!IsProxy(promiseObj)) {
   2299    promise = &promiseObj->as<PromiseObject>();
   2300  } else {
   2301    JSObject* unwrappedPromiseObj = UncheckedUnwrap(promiseObj);
   2302    if (JS_IsDeadWrapper(unwrappedPromiseObj)) {
   2303      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   2304                                JSMSG_DEAD_OBJECT);
   2305      return false;
   2306    }
   2307    promise = &unwrappedPromiseObj->as<PromiseObject>();
   2308    ar.emplace(cx, promise);
   2309 
   2310    // The rejection reason might've been created in a compartment with higher
   2311    // privileges than the Promise's. In that case, object-type rejection
   2312    // values might be wrapped into a wrapper that throws whenever the
   2313    // Promise's reaction handler wants to do anything useful with it. To
   2314    // avoid that situation, we synthesize a generic error that doesn't
   2315    // expose any privileged information but can safely be used in the
   2316    // rejection handler.
   2317    if (!cx->compartment()->wrap(cx, &reason)) {
   2318      return false;
   2319    }
   2320    if (reason.isObject() && !CheckedUnwrapStatic(&reason.toObject())) {
   2321      // Report the existing reason, so we don't just drop it on the
   2322      // floor.
   2323      JSObject* realReason = UncheckedUnwrap(&reason.toObject());
   2324      RootedValue realReasonVal(cx, ObjectValue(*realReason));
   2325      Rooted<GlobalObject*> realGlobal(cx, &realReason->nonCCWGlobal());
   2326      ReportErrorToGlobal(cx, realGlobal, realReasonVal);
   2327 
   2328      // Async stacks are only properly adopted if there's at least one
   2329      // interpreter frame active right now. If a thenable job with a
   2330      // throwing `then` function got us here, that'll not be the case,
   2331      // so we add one by throwing the error from self-hosted code.
   2332      if (!GetInternalError(cx, JSMSG_PROMISE_ERROR_IN_WRAPPED_REJECTION_REASON,
   2333                            &reason)) {
   2334        return false;
   2335      }
   2336    }
   2337  }
   2338 
   2339  return ResolvePromise(cx, promise, reason, JS::PromiseState::Rejected,
   2340                        unwrappedRejectionStack);
   2341 }
   2342 
   2343 // Apply f to a mutable handle on each member of a collection of reactions, like
   2344 // that stored in PromiseSlot_ReactionsOrResult on a pending promise. When the
   2345 // reaction record is wrapped, we pass the wrapper, without dereferencing it. If
   2346 // f returns false, then we stop the iteration immediately and return false.
   2347 // Otherwise, we return true.
   2348 //
   2349 // There are several different representations for collections:
   2350 //
   2351 // - We represent an empty collection of reactions as an 'undefined' value.
   2352 //
   2353 // - We represent a collection containing a single reaction simply as the given
   2354 //   PromiseReactionRecord object, possibly wrapped.
   2355 //
   2356 // - We represent a collection of two or more reactions as a dense array of
   2357 //   possibly-wrapped PromiseReactionRecords.
   2358 //
   2359 template <typename F>
   2360 static bool ForEachReaction(JSContext* cx, HandleValue reactionsVal, F f) {
   2361  if (reactionsVal.isUndefined()) {
   2362    return true;
   2363  }
   2364 
   2365  RootedObject reactions(cx, &reactionsVal.toObject());
   2366  RootedObject reaction(cx);
   2367 
   2368  if (reactions->is<PromiseReactionRecord>() || IsWrapper(reactions) ||
   2369      JS_IsDeadWrapper(reactions)) {
   2370    return f(&reactions);
   2371  }
   2372 
   2373  Handle<NativeObject*> reactionsList = reactions.as<NativeObject>();
   2374  uint32_t reactionsCount = reactionsList->getDenseInitializedLength();
   2375  MOZ_ASSERT(reactionsCount > 1, "Reactions list should be created lazily");
   2376 
   2377  for (uint32_t i = 0; i < reactionsCount; i++) {
   2378    const Value& reactionVal = reactionsList->getDenseElement(i);
   2379    MOZ_RELEASE_ASSERT(reactionVal.isObject());
   2380    reaction = &reactionVal.toObject();
   2381    if (!f(&reaction)) {
   2382      return false;
   2383    }
   2384  }
   2385 
   2386  return true;
   2387 }
   2388 
   2389 /**
   2390 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   2391 *
   2392 * TriggerPromiseReactions ( reactions, argument )
   2393 * https://tc39.es/ecma262/#sec-triggerpromisereactions
   2394 */
   2395 [[nodiscard]] static bool TriggerPromiseReactions(JSContext* cx,
   2396                                                  HandleValue reactionsVal,
   2397                                                  JS::PromiseState state,
   2398                                                  HandleValue valueOrReason) {
   2399  MOZ_ASSERT(state == JS::PromiseState::Fulfilled ||
   2400             state == JS::PromiseState::Rejected);
   2401 
   2402  // Step 1. For each element reaction of reactions, do
   2403  // Step 2. Return undefined.
   2404  return ForEachReaction(cx, reactionsVal, [&](MutableHandleObject reaction) {
   2405    // Step 1.a. Let job be NewPromiseReactionJob(reaction, argument).
   2406    // Step 1.b. Perform HostEnqueuePromiseJob(job.[[Job]], job.[[Realm]]).
   2407    return EnqueuePromiseReactionJob(cx, reaction, valueOrReason, state);
   2408  });
   2409 }
   2410 
   2411 [[nodiscard]] static bool CallPromiseResolveFunction(JSContext* cx,
   2412                                                     HandleObject resolveFun,
   2413                                                     HandleValue value,
   2414                                                     HandleObject promiseObj);
   2415 
   2416 /**
   2417 * ES2023 draft rev 714fa3dd1e8237ae9c666146270f81880089eca5
   2418 *
   2419 * NewPromiseReactionJob ( reaction, argument )
   2420 * https://tc39.es/ecma262/#sec-newpromisereactionjob
   2421 *
   2422 * Step 1.
   2423 *
   2424 * Implements PromiseReactionJob optimized for the case when the reaction
   2425 * handler is one of the default resolving functions as created by the
   2426 * CreateResolvingFunctions abstract operation.
   2427 */
   2428 [[nodiscard]] static bool DefaultResolvingPromiseReactionJob(
   2429    JSContext* cx, Handle<PromiseReactionRecord*> reaction) {
   2430  MOZ_ASSERT(reaction->targetState() != JS::PromiseState::Pending);
   2431 
   2432  Rooted<PromiseObject*> promiseToResolve(cx,
   2433                                          reaction->defaultResolvingPromise());
   2434 
   2435  // Testing functions allow to directly settle a promise without going
   2436  // through the resolving functions. In that case the normal bookkeeping to
   2437  // ensure only pending promises can be resolved doesn't apply and we need
   2438  // to manually check for already settled promises. We still call
   2439  // Run{Fulfill,Reject}Function for consistency with PromiseReactionJob.
   2440  ResolutionMode resolutionMode = ResolveMode;
   2441  RootedValue handlerResult(cx, UndefinedValue());
   2442  Rooted<SavedFrame*> unwrappedRejectionStack(cx);
   2443  if (promiseToResolve->state() == JS::PromiseState::Pending) {
   2444    RootedValue argument(cx, reaction->handlerArg());
   2445 
   2446    // Step 1.e. Else, let handlerResult be
   2447    //           Completion(HostCallJobCallback(handler, undefined,
   2448    //                                          « argument »)).
   2449    bool ok;
   2450    if (reaction->targetState() == JS::PromiseState::Fulfilled) {
   2451      ok = ResolvePromiseInternal(cx, promiseToResolve, argument);
   2452    } else {
   2453      ok = RejectPromiseInternal(cx, promiseToResolve, argument);
   2454    }
   2455 
   2456    if (!ok) {
   2457      resolutionMode = RejectMode;
   2458      if (!MaybeGetAndClearExceptionAndStack(cx, &handlerResult,
   2459                                             &unwrappedRejectionStack)) {
   2460        return false;
   2461      }
   2462    }
   2463  }
   2464 
   2465  // Steps 1.f-i.
   2466  RootedObject promiseObj(cx, reaction->promise());
   2467  RootedObject callee(cx);
   2468  if (resolutionMode == ResolveMode) {
   2469    callee =
   2470        reaction->getFixedSlot(PromiseReactionRecord::Resolve).toObjectOrNull();
   2471 
   2472    return CallPromiseResolveFunction(cx, callee, handlerResult, promiseObj);
   2473  }
   2474 
   2475  callee =
   2476      reaction->getFixedSlot(PromiseReactionRecord::Reject).toObjectOrNull();
   2477 
   2478  return CallPromiseRejectFunction(cx, callee, handlerResult, promiseObj,
   2479                                   unwrappedRejectionStack,
   2480                                   reaction->unhandledRejectionBehavior());
   2481 }
   2482 
   2483 /**
   2484 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   2485 *
   2486 * Await in async function
   2487 * https://tc39.es/ecma262/#await
   2488 *
   2489 * Step 3. fulfilledClosure Abstract Closure.
   2490 * Step 5. rejectedClosure Abstract Closure.
   2491 */
   2492 [[nodiscard]] static bool AsyncFunctionPromiseReactionJob(
   2493    JSContext* cx, Handle<PromiseReactionRecord*> reaction) {
   2494  MOZ_ASSERT(reaction->isAsyncFunction());
   2495 
   2496  auto handler = static_cast<PromiseHandler>(reaction->handler().toInt32());
   2497  RootedValue argument(cx, reaction->handlerArg());
   2498  Rooted<AsyncFunctionGeneratorObject*> generator(
   2499      cx, reaction->asyncFunctionGenerator());
   2500 
   2501  // Await's handlers don't return a value, nor throw any exceptions.
   2502  // They fail only on OOM.
   2503 
   2504  if (handler == PromiseHandler::AsyncFunctionAwaitedFulfilled) {
   2505    // Step 3. fulfilledClosure Abstract Closure.
   2506    return AsyncFunctionAwaitedFulfilled(cx, generator, argument);
   2507  }
   2508 
   2509  // Step 5. rejectedClosure Abstract Closure.
   2510  MOZ_ASSERT(handler == PromiseHandler::AsyncFunctionAwaitedRejected);
   2511  return AsyncFunctionAwaitedRejected(cx, generator, argument);
   2512 }
   2513 
   2514 /**
   2515 * ES2023 draft rev 714fa3dd1e8237ae9c666146270f81880089eca5
   2516 *
   2517 * NewPromiseReactionJob ( reaction, argument )
   2518 * https://tc39.es/ecma262/#sec-newpromisereactionjob
   2519 *
   2520 * Step 1.
   2521 *
   2522 * Callback triggering the fulfill/reject reaction for a resolved Promise,
   2523 * to be invoked by the embedding during its processing of the Promise job
   2524 * queue.
   2525 *
   2526 * A PromiseReactionJob is set as the native function of an extended
   2527 * JSFunction object, with all information required for the job's
   2528 * execution stored in in a reaction record in its first extended slot.
   2529 */
   2530 static bool PromiseReactionJob(JSContext* cx, HandleObject reactionObjIn) {
   2531  RootedObject reactionObj(cx, reactionObjIn);
   2532  // To ensure that the embedding ends up with the right entry global, we're
   2533  // guaranteeing that the reaction job function gets created in the same
   2534  // compartment as the handler function. That's not necessarily the global
   2535  // that the job was triggered from, though.
   2536  // We can find the triggering global via the job's reaction record. To go
   2537  // back, we check if the reaction is a wrapper and if so, unwrap it and
   2538  // enter its compartment.
   2539  //
   2540  // MG:XXX: I think that when we switch over to using the JS microtask
   2541  // queue exclusively there's some cleanup around realm handling possible.
   2542  mozilla::Maybe<AutoRealm> ar;
   2543  if (!IsProxy(reactionObj)) {
   2544    MOZ_RELEASE_ASSERT(reactionObj->is<PromiseReactionRecord>());
   2545  } else {
   2546    reactionObj = UncheckedUnwrap(reactionObj);
   2547    if (JS_IsDeadWrapper(reactionObj)) {
   2548      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   2549                                JSMSG_DEAD_OBJECT);
   2550      return false;
   2551    }
   2552    MOZ_RELEASE_ASSERT(reactionObj->is<PromiseReactionRecord>());
   2553    ar.emplace(cx, reactionObj);
   2554  }
   2555 
   2556  // Optimized/special cases.
   2557  Handle<PromiseReactionRecord*> reaction =
   2558      reactionObj.as<PromiseReactionRecord>();
   2559  if (reaction->isDefaultResolvingHandler()) {
   2560    return DefaultResolvingPromiseReactionJob(cx, reaction);
   2561  }
   2562  if (reaction->isAsyncFunction()) {
   2563    MOZ_RELEASE_ASSERT(reaction->asyncFunctionGenerator()->realm() ==
   2564                       cx->realm());
   2565    return AsyncFunctionPromiseReactionJob(cx, reaction);
   2566  }
   2567  if (reaction->isAsyncGenerator()) {
   2568    RootedValue argument(cx, reaction->handlerArg());
   2569    Rooted<AsyncGeneratorObject*> generator(cx, reaction->asyncGenerator());
   2570    auto handler = static_cast<PromiseHandler>(reaction->handler().toInt32());
   2571    return AsyncGeneratorPromiseReactionJob(cx, handler, generator, argument);
   2572  }
   2573  if (reaction->isDebuggerDummy()) {
   2574    return true;
   2575  }
   2576 
   2577  // Step 1.a. Let promiseCapability be reaction.[[Capability]].
   2578  // (implicit)
   2579 
   2580  // Step 1.c. Let handler be reaction.[[Handler]].
   2581  RootedValue handlerVal(cx, reaction->handler());
   2582 
   2583  RootedValue argument(cx, reaction->handlerArg());
   2584 
   2585  RootedValue handlerResult(cx);
   2586  ResolutionMode resolutionMode = ResolveMode;
   2587 
   2588  Rooted<SavedFrame*> unwrappedRejectionStack(cx);
   2589 
   2590  // Step 1.d. If handler is empty, then
   2591  if (handlerVal.isInt32()) {
   2592    // Step 1.b. Let type be reaction.[[Type]].
   2593    // (reordered)
   2594    auto handlerNum = static_cast<PromiseHandler>(handlerVal.toInt32());
   2595 
   2596    // Step 1.d.i. If type is Fulfill, let handlerResult be
   2597    //             NormalCompletion(argument).
   2598    if (handlerNum == PromiseHandler::Identity) {
   2599      handlerResult = argument;
   2600    } else if (handlerNum == PromiseHandler::Thrower) {
   2601      // Step 1.d.ii. Else,
   2602      // Step 1.d.ii.1. Assert: type is Reject.
   2603      // Step 1.d.ii.2. Let handlerResult be ThrowCompletion(argument).
   2604      resolutionMode = RejectMode;
   2605      handlerResult = argument;
   2606    }
   2607 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
   2608    else if (handlerNum == PromiseHandler::AsyncIteratorDisposeAwaitFulfilled) {
   2609      // Explicit Resource Management Proposal
   2610      // 27.1.3.1 %AsyncIteratorPrototype% [ @@asyncDispose ] ( )
   2611      // https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-%25asynciteratorprototype%25-%40%40asyncdispose
   2612      //
   2613      // Step 6.e.i. Return undefined.
   2614      handlerResult = JS::UndefinedValue();
   2615    }
   2616 #endif
   2617    else if (handlerNum == PromiseHandler::AsyncFromSyncIteratorClose) {
   2618      MOZ_ASSERT(reaction->isAsyncFromSyncIterator());
   2619 
   2620      // 27.1.6.4 AsyncFromSyncIteratorContinuation
   2621      //
   2622      // Step 13.a.i. Return ? IteratorClose(syncIteratorRecord,
   2623      //              ThrowCompletion(error)).
   2624      //
   2625      // https://tc39.es/ecma262/#sec-asyncfromsynciteratorcontinuation
   2626      Rooted<JSObject*> iter(cx, reaction->asyncFromSyncIterator()->iterator());
   2627      MOZ_ALWAYS_TRUE(CloseIterOperation(cx, iter, CompletionKind::Throw));
   2628 
   2629      resolutionMode = RejectMode;
   2630      handlerResult = argument;
   2631    } else {
   2632      // Special case for Async-from-Sync Iterator.
   2633 
   2634      MOZ_ASSERT(handlerNum ==
   2635                     PromiseHandler::AsyncFromSyncIteratorValueUnwrapDone ||
   2636                 handlerNum ==
   2637                     PromiseHandler::AsyncFromSyncIteratorValueUnwrapNotDone);
   2638 
   2639      bool done =
   2640          handlerNum == PromiseHandler::AsyncFromSyncIteratorValueUnwrapDone;
   2641 
   2642      // 27.1.6.4 AsyncFromSyncIteratorContinuation
   2643      //
   2644      // Step 9.a. Return CreateIteratorResultObject(v, done).
   2645      //
   2646      // https://tc39.es/ecma262/#sec-asyncfromsynciteratorcontinuation
   2647      PlainObject* resultObj = CreateIterResultObject(cx, argument, done);
   2648      if (!resultObj) {
   2649        return false;
   2650      }
   2651 
   2652      handlerResult = ObjectValue(*resultObj);
   2653    }
   2654  } else {
   2655    MOZ_ASSERT(handlerVal.isObject());
   2656    MOZ_ASSERT(IsCallable(handlerVal));
   2657 
   2658    // Step 1.e. Else, let handlerResult be
   2659    //           Completion(HostCallJobCallback(handler, undefined,
   2660    //                                          « argument »)).
   2661    if (!Call(cx, handlerVal, UndefinedHandleValue, argument, &handlerResult)) {
   2662      resolutionMode = RejectMode;
   2663      if (!MaybeGetAndClearExceptionAndStack(cx, &handlerResult,
   2664                                             &unwrappedRejectionStack)) {
   2665        return false;
   2666      }
   2667    }
   2668  }
   2669 
   2670  // Steps 1.f-i.
   2671  RootedObject promiseObj(cx, reaction->promise());
   2672  RootedObject callee(cx);
   2673  if (resolutionMode == ResolveMode) {
   2674    callee =
   2675        reaction->getFixedSlot(PromiseReactionRecord::Resolve).toObjectOrNull();
   2676 
   2677    return CallPromiseResolveFunction(cx, callee, handlerResult, promiseObj);
   2678  }
   2679 
   2680  callee =
   2681      reaction->getFixedSlot(PromiseReactionRecord::Reject).toObjectOrNull();
   2682 
   2683  return CallPromiseRejectFunction(cx, callee, handlerResult, promiseObj,
   2684                                   unwrappedRejectionStack,
   2685                                   reaction->unhandledRejectionBehavior());
   2686 }
   2687 
   2688 static bool PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp) {
   2689  CallArgs args = CallArgsFromVp(argc, vp);
   2690 
   2691  RootedFunction job(cx, &args.callee().as<JSFunction>());
   2692 
   2693  // Promise reactions don't return any value.
   2694  args.rval().setUndefined();
   2695 
   2696  RootedObject reactionObj(
   2697      cx, &job->getExtendedSlot(ReactionJobSlot_ReactionRecord).toObject());
   2698  return PromiseReactionJob(cx, reactionObj);
   2699 }
   2700 
   2701 /**
   2702 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   2703 *
   2704 * NewPromiseResolveThenableJob ( promiseToResolve, thenable, then )
   2705 * https://tc39.es/ecma262/#sec-newpromiseresolvethenablejob
   2706 *
   2707 * Steps 1.a-d.
   2708 *
   2709 * A PromiseResolveThenableJob is set as the native function of an extended
   2710 * JSFunction object, with all information required for the job's
   2711 * execution stored in the function's extended slots.
   2712 */
   2713 static bool PromiseResolveThenableJob(JSContext* cx, HandleObject promise,
   2714                                      HandleValue thenable, HandleObject then) {
   2715  // Step 1.a. Let resolvingFunctions be
   2716  //           CreateResolvingFunctions(promiseToResolve).
   2717  RootedObject resolveFn(cx);
   2718  RootedObject rejectFn(cx);
   2719  if (!CreateResolvingFunctions(cx, promise, &resolveFn, &rejectFn)) {
   2720    return false;
   2721  }
   2722 
   2723  // Step 1.b. Let thenCallResult be
   2724  //           HostCallJobCallback(then, thenable,
   2725  //                               « resolvingFunctions.[[Resolve]],
   2726  //                                 resolvingFunctions.[[Reject]] »).
   2727  FixedInvokeArgs<2> args2(cx);
   2728  args2[0].setObject(*resolveFn);
   2729  args2[1].setObject(*rejectFn);
   2730 
   2731  // In difference to the usual pattern, we return immediately on success.
   2732  RootedValue rval(cx);
   2733  if (Call(cx, thenable, then, args2, &rval)) {
   2734    // Step 1.d. Return Completion(thenCallResult).
   2735    return true;
   2736  }
   2737 
   2738  // Step 1.c. If thenCallResult is an abrupt completion, then
   2739 
   2740  Rooted<SavedFrame*> stack(cx);
   2741  if (!MaybeGetAndClearExceptionAndStack(cx, &rval, &stack)) {
   2742    return false;
   2743  }
   2744 
   2745  // Step 1.c.i. Let status be
   2746  //             Call(resolvingFunctions.[[Reject]], undefined,
   2747  //                  « thenCallResult.[[Value]] »).
   2748  // Step 1.c.ii. Return Completion(status).
   2749  RootedValue rejectVal(cx, ObjectValue(*rejectFn));
   2750  return Call(cx, rejectVal, UndefinedHandleValue, rval, &rval);
   2751 }
   2752 
   2753 /*
   2754 * Usage of the function's extended slots is described in the ThenableJobSlots
   2755 * enum.
   2756 */
   2757 static bool PromiseResolveThenableJob(JSContext* cx, unsigned argc, Value* vp) {
   2758  CallArgs args = CallArgsFromVp(argc, vp);
   2759 
   2760  RootedFunction job(cx, &args.callee().as<JSFunction>());
   2761  RootedObject promise(
   2762      cx, &job->getExtendedSlot(ThenableJobSlot_Promise).toObject());
   2763  RootedValue thenable(cx, job->getExtendedSlot(ThenableJobSlot_Thenable));
   2764  RootedObject then(cx,
   2765                    &job->getExtendedSlot(ThenableJobSlot_Handler).toObject());
   2766 
   2767  return PromiseResolveThenableJob(cx, promise, thenable, then);
   2768 }
   2769 
   2770 [[nodiscard]] static bool OriginalPromiseThenWithoutSettleHandlers(
   2771    JSContext* cx, Handle<PromiseObject*> promise,
   2772    Handle<PromiseObject*> promiseToResolve);
   2773 
   2774 /**
   2775 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   2776 *
   2777 * NewPromiseResolveThenableJob ( promiseToResolve, thenable, then )
   2778 * https://tc39.es/ecma262/#sec-newpromiseresolvethenablejob
   2779 *
   2780 * Step 1.a-d.
   2781 *
   2782 * Specialization of PromiseResolveThenableJob when the `thenable` is a
   2783 * built-in Promise object and the `then` property is the built-in
   2784 * `Promise.prototype.then` function.
   2785 *
   2786 * A PromiseResolveBuiltinThenableJob is set as the native function of an
   2787 * extended JSFunction object, with all information required for the job's
   2788 * execution stored in the function's extended slots.
   2789 *
   2790 * Usage of the function's extended slots is described in the ThenableJobSlots
   2791 * enum.
   2792 */
   2793 static bool PromiseResolveBuiltinThenableJob(JSContext* cx,
   2794                                             HandleObject promise,
   2795                                             HandleObject thenable) {
   2796  cx->check(promise, thenable);
   2797  MOZ_ASSERT(promise->is<PromiseObject>());
   2798  MOZ_ASSERT(thenable->is<PromiseObject>());
   2799 
   2800  // Step 1.a. Let resolvingFunctions be
   2801  //           CreateResolvingFunctions(promiseToResolve).
   2802  // (skipped)
   2803 
   2804  // Step 1.b. Let thenCallResult be HostCallJobCallback(
   2805  //             then, thenable,
   2806  //             « resolvingFunctions.[[Resolve]],
   2807  //               resolvingFunctions.[[Reject]] »).
   2808  //
   2809  // NOTE: In difference to the usual pattern, we return immediately on success.
   2810  if (OriginalPromiseThenWithoutSettleHandlers(cx, thenable.as<PromiseObject>(),
   2811                                               promise.as<PromiseObject>())) {
   2812    // Step 1.d. Return Completion(thenCallResult).
   2813    return true;
   2814  }
   2815 
   2816  // Step 1.c. If thenCallResult is an abrupt completion, then
   2817  RootedValue exception(cx);
   2818  Rooted<SavedFrame*> stack(cx);
   2819  if (!MaybeGetAndClearExceptionAndStack(cx, &exception, &stack)) {
   2820    return false;
   2821  }
   2822 
   2823  // Testing functions allow to directly settle a promise without going
   2824  // through the resolving functions. In that case the normal bookkeeping to
   2825  // ensure only pending promises can be resolved doesn't apply and we need
   2826  // to manually check for already settled promises. The exception is simply
   2827  // dropped when this case happens.
   2828  if (promise->as<PromiseObject>().state() != JS::PromiseState::Pending) {
   2829    return true;
   2830  }
   2831 
   2832  // Step 1.c.i. Let status be
   2833  //             Call(resolvingFunctions.[[Reject]], undefined,
   2834  //                  « thenCallResult.[[Value]] »).
   2835  // Step 1.c.ii. Return Completion(status).
   2836  return RejectPromiseInternal(cx, promise.as<PromiseObject>(), exception,
   2837                               stack);
   2838 }
   2839 
   2840 static bool PromiseResolveBuiltinThenableJob(JSContext* cx, unsigned argc,
   2841                                             Value* vp) {
   2842  CallArgs args = CallArgsFromVp(argc, vp);
   2843 
   2844  RootedFunction job(cx, &args.callee().as<JSFunction>());
   2845  RootedObject promise(
   2846      cx, &job->getExtendedSlot(ThenableJobSlot_Promise).toObject());
   2847  RootedObject thenable(
   2848      cx, &job->getExtendedSlot(ThenableJobSlot_Thenable).toObject());
   2849  // The handler slot is not used for builtin `then`.
   2850  MOZ_ASSERT(job->getExtendedSlot(ThenableJobSlot_Handler).isUndefined());
   2851 
   2852  return PromiseResolveBuiltinThenableJob(cx, promise, thenable);
   2853 }
   2854 
   2855 /**
   2856 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   2857 *
   2858 * NewPromiseResolveThenableJob ( promiseToResolve, thenable, then )
   2859 * https://tc39.es/ecma262/#sec-newpromiseresolvethenablejob
   2860 * HostEnqueuePromiseJob ( job, realm )
   2861 * https://tc39.es/ecma262/#sec-hostenqueuepromisejob
   2862 *
   2863 * Tells the embedding to enqueue a Promise resolve thenable job, based on
   2864 * three parameters:
   2865 * promiseToResolve_ - The promise to resolve, obviously.
   2866 * thenable_ - The thenable to resolve the Promise with.
   2867 * thenVal - The `then` function to invoke with the `thenable` as the receiver.
   2868 */
   2869 [[nodiscard]] static bool EnqueuePromiseResolveThenableJob(
   2870    JSContext* cx, HandleValue promiseToResolve_, HandleValue thenable_,
   2871    HandleValue thenVal) {
   2872  // Need to re-root these to enable wrapping them below.
   2873  RootedValue promiseToResolve(cx, promiseToResolve_);
   2874  RootedValue thenable(cx, thenable_);
   2875 
   2876  // Step 2. Let getThenRealmResult be GetFunctionRealm(then.[[Callback]]).
   2877  // Step 3. If getThenRealmResult is a normal completion, let thenRealm be
   2878  //         getThenRealmResult.[[Value]].
   2879  // Step 4. Else, let thenRealm be the current Realm Record.
   2880  // Step 5. NOTE: thenRealm is never null. When then.[[Callback]] is a revoked
   2881  //         Proxy and no code runs, thenRealm is used to create error objects.
   2882  //
   2883  // NOTE: Instead of passing job and realm separately, we use the job's
   2884  //       JSFunction object's realm as the job's realm.
   2885  //       So we should enter the thenRealm before creating the job function.
   2886  //
   2887  // GetFunctionRealm performed inside AutoFunctionOrCurrentRealm uses checked
   2888  // unwrap and this is fine given the behavior difference (see the comment
   2889  // around AutoFunctionOrCurrentRealm usage in EnqueuePromiseReactionJob for
   2890  // more details) is observable only when the `thenable` is from content realm
   2891  // and `then` is from chrome realm, that shouldn't happen in practice.
   2892  //
   2893  // NOTE: If `thenable` is also from chrome realm, accessing `then` silently
   2894  //       fails and it returns `undefined`, and that case doesn't reach here.
   2895  RootedObject then(cx, &thenVal.toObject());
   2896  AutoFunctionOrCurrentRealm ar(cx, then);
   2897  if (then->maybeCCWRealm() != cx->realm()) {
   2898    if (!cx->compartment()->wrap(cx, &then)) {
   2899      return false;
   2900    }
   2901  }
   2902 
   2903  // Wrap the `promiseToResolve` and `thenable` arguments.
   2904  if (!cx->compartment()->wrap(cx, &promiseToResolve)) {
   2905    return false;
   2906  }
   2907 
   2908  MOZ_ASSERT(thenable.isObject());
   2909  if (!cx->compartment()->wrap(cx, &thenable)) {
   2910    return false;
   2911  }
   2912 
   2913  // At this point the promise is guaranteed to be wrapped into the job's
   2914  // compartment.
   2915  RootedObject promise(cx, &promiseToResolve.toObject());
   2916 
   2917  if (JS::Prefs::use_js_microtask_queue()) {
   2918    RootedObject hostDefinedGlobalRepresentative(cx);
   2919    {
   2920      RootedObject hostDefinedGlobal(cx);
   2921      if (!cx->jobQueue->getHostDefinedGlobal(cx, &hostDefinedGlobal)) {
   2922        return false;
   2923      }
   2924 
   2925      MOZ_ASSERT_IF(hostDefinedGlobal, hostDefinedGlobal->is<GlobalObject>());
   2926      if (hostDefinedGlobal) {
   2927        hostDefinedGlobalRepresentative =
   2928            &hostDefinedGlobal->as<GlobalObject>().getObjectPrototype();
   2929      }
   2930    }
   2931 
   2932    // Wrap the representative.
   2933    if (!cx->compartment()->wrap(cx, &hostDefinedGlobalRepresentative)) {
   2934      return false;
   2935    }
   2936 
   2937    ThenableJob* thenableJob =
   2938        NewThenableJob(cx, ThenableJob::PromiseResolveThenableJob, promise,
   2939                       thenable, then, HostDefinedDataIsOptimizedOut);
   2940    if (!thenableJob) {
   2941      return false;
   2942    }
   2943 
   2944    thenableJob->setHostDefinedGlobalRepresentative(
   2945        hostDefinedGlobalRepresentative);
   2946    return EnqueueJob(cx, thenableJob);
   2947  }
   2948 
   2949  // Step 1. Let job be a new Job Abstract Closure with no parameters that
   2950  //         captures promiseToResolve, thenable, and then and performs the
   2951  //         following steps when called:
   2952  Handle<PropertyName*> funName = cx->names().empty_;
   2953  RootedFunction job(
   2954      cx, NewNativeFunction(cx, PromiseResolveThenableJob, 0, funName,
   2955                            gc::AllocKind::FUNCTION_EXTENDED, GenericObject));
   2956  if (!job) {
   2957    return false;
   2958  }
   2959 
   2960  // Set the `promiseToResolve`, `thenable` and `then` arguments on the
   2961  // callback.
   2962  job->setExtendedSlot(ThenableJobSlot_Promise, promiseToResolve);
   2963  job->setExtendedSlot(ThenableJobSlot_Thenable, thenable);
   2964  job->setExtendedSlot(ThenableJobSlot_Handler, ObjectValue(*then));
   2965 
   2966  // Step X. HostEnqueuePromiseJob(job.[[Job]], job.[[Realm]]).
   2967  return cx->runtime()->enqueuePromiseJob(cx, job, promise,
   2968                                          HostDefinedDataIsOptimizedOut);
   2969 }
   2970 
   2971 /**
   2972 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   2973 *
   2974 * NewPromiseResolveThenableJob ( promiseToResolve, thenable, then )
   2975 * https://tc39.es/ecma262/#sec-newpromiseresolvethenablejob
   2976 * HostEnqueuePromiseJob ( job, realm )
   2977 * https://tc39.es/ecma262/#sec-hostenqueuepromisejob
   2978 *
   2979 * Tells the embedding to enqueue a Promise resolve thenable built-in job,
   2980 * based on two parameters:
   2981 * promiseToResolve - The promise to resolve, obviously.
   2982 * thenable - The thenable to resolve the Promise with.
   2983 */
   2984 [[nodiscard]] static bool EnqueuePromiseResolveThenableBuiltinJob(
   2985    JSContext* cx, HandleObject promiseToResolve, HandleObject thenable) {
   2986  cx->check(promiseToResolve, thenable);
   2987  MOZ_ASSERT(promiseToResolve->is<PromiseObject>());
   2988  MOZ_ASSERT(thenable->is<PromiseObject>());
   2989 
   2990  if (JS::Prefs::use_js_microtask_queue()) {
   2991    // Step 1. Let job be a new Job Abstract Closure with no parameters that
   2992 
   2993    Rooted<JSObject*> hostDefinedData(cx);
   2994    if (!cx->runtime()->getHostDefinedData(cx, &hostDefinedData)) {
   2995      return false;
   2996    }
   2997 
   2998    RootedValue thenableValue(cx, ObjectValue(*thenable));
   2999    ThenableJob* thenableJob = NewThenableJob(
   3000        cx, ThenableJob::PromiseResolveBuiltinThenableJob, promiseToResolve,
   3001        thenableValue, nullptr, hostDefinedData);
   3002    if (!thenableJob) {
   3003      return false;
   3004    }
   3005 
   3006    return EnqueueJob(cx, thenableJob);
   3007  }
   3008 
   3009  // Step 1. Let job be a new Job Abstract Closure with no parameters that
   3010  //         captures promiseToResolve, thenable, and then and performs the
   3011  //         following steps when called:
   3012  Handle<PropertyName*> funName = cx->names().empty_;
   3013  RootedFunction job(
   3014      cx, NewNativeFunction(cx, PromiseResolveBuiltinThenableJob, 0, funName,
   3015                            gc::AllocKind::FUNCTION_EXTENDED, GenericObject));
   3016  if (!job) {
   3017    return false;
   3018  }
   3019 
   3020  // Steps 2-5.
   3021  // (implicit)
   3022  // `then` is built-in Promise.prototype.then in the current realm.,
   3023  // thus `thenRealm` is also current realm, and we have nothing to do here.
   3024 
   3025  // Store the promise and the thenable on the reaction job.
   3026  job->setExtendedSlot(ThenableJobSlot_Promise, ObjectValue(*promiseToResolve));
   3027  job->setExtendedSlot(ThenableJobSlot_Thenable, ObjectValue(*thenable));
   3028 
   3029  Rooted<JSObject*> hostDefinedData(cx);
   3030  if (!cx->runtime()->getHostDefinedData(cx, &hostDefinedData)) {
   3031    return false;
   3032  }
   3033 
   3034  // HostEnqueuePromiseJob(job.[[Job]], job.[[Realm]]).
   3035  return cx->runtime()->enqueuePromiseJob(cx, job, promiseToResolve,
   3036                                          hostDefinedData);
   3037 }
   3038 
   3039 [[nodiscard]] static bool AddDummyPromiseReactionForDebugger(
   3040    JSContext* cx, Handle<PromiseObject*> promise,
   3041    HandleObject dependentPromise);
   3042 
   3043 [[nodiscard]] static bool AddPromiseReaction(
   3044    JSContext* cx, Handle<PromiseObject*> promise,
   3045    Handle<PromiseReactionRecord*> reaction);
   3046 
   3047 static JSFunction* GetResolveFunctionFromReject(JSFunction* reject) {
   3048  MOZ_ASSERT(reject->maybeNative() == RejectPromiseFunction);
   3049  Value resolveFunVal =
   3050      reject->getExtendedSlot(RejectFunctionSlot_ResolveFunction);
   3051  MOZ_ASSERT(IsNativeFunction(resolveFunVal, ResolvePromiseFunction));
   3052  return &resolveFunVal.toObject().as<JSFunction>();
   3053 }
   3054 
   3055 static JSFunction* GetRejectFunctionFromResolve(JSFunction* resolve) {
   3056  MOZ_ASSERT(resolve->maybeNative() == ResolvePromiseFunction);
   3057  Value rejectFunVal =
   3058      resolve->getExtendedSlot(ResolveFunctionSlot_RejectFunction);
   3059  MOZ_ASSERT(IsNativeFunction(rejectFunVal, RejectPromiseFunction));
   3060  return &rejectFunVal.toObject().as<JSFunction>();
   3061 }
   3062 
   3063 static JSFunction* GetResolveFunctionFromPromise(PromiseObject* promise) {
   3064  Value rejectFunVal = promise->getFixedSlot(PromiseSlot_RejectFunction);
   3065  if (rejectFunVal.isUndefined()) {
   3066    return nullptr;
   3067  }
   3068  JSObject* rejectFunObj = &rejectFunVal.toObject();
   3069 
   3070  // We can safely unwrap it because all we want is to get the resolve
   3071  // function.
   3072  if (IsWrapper(rejectFunObj)) {
   3073    rejectFunObj = UncheckedUnwrap(rejectFunObj);
   3074  }
   3075 
   3076  if (!rejectFunObj->is<JSFunction>()) {
   3077    return nullptr;
   3078  }
   3079 
   3080  JSFunction* rejectFun = &rejectFunObj->as<JSFunction>();
   3081 
   3082  // Only the original RejectPromiseFunction has a reference to the resolve
   3083  // function.
   3084  if (rejectFun->maybeNative() != &RejectPromiseFunction) {
   3085    return nullptr;
   3086  }
   3087 
   3088  // The reject function was already called and cleared its resolve-function
   3089  // extended slot.
   3090  if (rejectFun->getExtendedSlot(RejectFunctionSlot_ResolveFunction)
   3091          .isUndefined()) {
   3092    return nullptr;
   3093  }
   3094 
   3095  return GetResolveFunctionFromReject(rejectFun);
   3096 }
   3097 
   3098 /**
   3099 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   3100 *
   3101 * Promise ( executor )
   3102 * https://tc39.es/ecma262/#sec-promise-executor
   3103 *
   3104 * Steps 3-7.
   3105 */
   3106 [[nodiscard]] static MOZ_ALWAYS_INLINE PromiseObject*
   3107 CreatePromiseObjectInternal(JSContext* cx, HandleObject proto /* = nullptr */,
   3108                            bool protoIsWrapped /* = false */,
   3109                            bool informDebugger /* = true */) {
   3110  // Enter the unwrapped proto's compartment, if that's different from
   3111  // the current one.
   3112  // All state stored in a Promise's fixed slots must be created in the
   3113  // same compartment, so we get all of that out of the way here.
   3114  // (Except for the resolution functions, which are created below.)
   3115  mozilla::Maybe<AutoRealm> ar;
   3116  if (protoIsWrapped) {
   3117    ar.emplace(cx, proto);
   3118  }
   3119 
   3120  // Step 3. Let promise be
   3121  //         ? OrdinaryCreateFromConstructor(
   3122  //             NewTarget, "%Promise.prototype%",
   3123  //             « [[PromiseState]], [[PromiseResult]],
   3124  //               [[PromiseFulfillReactions]], [[PromiseRejectReactions]],
   3125  //               [[PromiseIsHandled]] »).
   3126  PromiseObject* promise = NewObjectWithClassProto<PromiseObject>(cx, proto);
   3127  if (!promise) {
   3128    return nullptr;
   3129  }
   3130 
   3131  // Step 4. Set promise.[[PromiseState]] to pending.
   3132  promise->initFixedSlot(PromiseSlot_Flags, Int32Value(0));
   3133 
   3134  // Step 5. Set promise.[[PromiseFulfillReactions]] to a new empty List.
   3135  // Step 6. Set promise.[[PromiseRejectReactions]] to a new empty List.
   3136  // (omitted)
   3137  // We allocate our single list of reaction records lazily.
   3138 
   3139  // Step 7. Set promise.[[PromiseIsHandled]] to false.
   3140  // (implicit)
   3141  // The handled flag is unset by default.
   3142 
   3143  if (MOZ_LIKELY(!JS::IsAsyncStackCaptureEnabledForRealm(cx))) {
   3144    return promise;
   3145  }
   3146 
   3147  // Store an allocation stack so we can later figure out what the
   3148  // control flow was for some unexpected results. Frightfully expensive,
   3149  // but oh well.
   3150 
   3151  Rooted<PromiseObject*> promiseRoot(cx, promise);
   3152 
   3153  PromiseDebugInfo* debugInfo = PromiseDebugInfo::create(cx, promiseRoot);
   3154  if (!debugInfo) {
   3155    return nullptr;
   3156  }
   3157 
   3158  // Let the Debugger know about this Promise.
   3159  if (informDebugger) {
   3160    DebugAPI::onNewPromise(cx, promiseRoot);
   3161  }
   3162 
   3163  return promiseRoot;
   3164 }
   3165 
   3166 /**
   3167 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   3168 *
   3169 * Promise ( executor )
   3170 * https://tc39.es/ecma262/#sec-promise-executor
   3171 */
   3172 static bool PromiseConstructor(JSContext* cx, unsigned argc, Value* vp) {
   3173  CallArgs args = CallArgsFromVp(argc, vp);
   3174 
   3175  // Step 1. If NewTarget is undefined, throw a TypeError exception.
   3176  if (!ThrowIfNotConstructing(cx, args, "Promise")) {
   3177    return false;
   3178  }
   3179 
   3180  // Step 2. If IsCallable(executor) is false, throw a TypeError exception.
   3181  HandleValue executorVal = args.get(0);
   3182  if (!IsCallable(executorVal)) {
   3183    return ReportIsNotFunction(cx, executorVal);
   3184  }
   3185  RootedObject executor(cx, &executorVal.toObject());
   3186 
   3187  RootedObject newTarget(cx, &args.newTarget().toObject());
   3188 
   3189  // If the constructor is called via an Xray wrapper, then the newTarget
   3190  // hasn't been unwrapped. We want that because, while the actual instance
   3191  // should be created in the target compartment, the constructor's code
   3192  // should run in the wrapper's compartment.
   3193  //
   3194  // This is so that the resolve and reject callbacks get created in the
   3195  // wrapper's compartment, which is required for code in that compartment
   3196  // to freely interact with it, and, e.g., pass objects as arguments, which
   3197  // it wouldn't be able to if the callbacks were themselves wrapped in Xray
   3198  // wrappers.
   3199  //
   3200  // At the same time, just creating the Promise itself in the wrapper's
   3201  // compartment wouldn't be helpful: if the wrapper forbids interactions
   3202  // with objects except for specific actions, such as calling them, then
   3203  // the code we want to expose it to can't actually treat it as a Promise:
   3204  // calling .then on it would throw, for example.
   3205  //
   3206  // Another scenario where it's important to create the Promise in a
   3207  // different compartment from the resolution functions is when we want to
   3208  // give non-privileged code a Promise resolved with the result of a
   3209  // Promise from privileged code; as a return value of a JS-implemented
   3210  // API, say. If the resolution functions were unprivileged, then resolving
   3211  // with a privileged Promise would cause `resolve` to attempt accessing
   3212  // .then on the passed Promise, which would throw an exception, so we'd
   3213  // just end up with a rejected Promise. Really, we want to chain the two
   3214  // Promises, with the unprivileged one resolved with the resolution of the
   3215  // privileged one.
   3216 
   3217  bool needsWrapping = false;
   3218  RootedObject proto(cx);
   3219  if (IsWrapper(newTarget)) {
   3220    JSObject* unwrappedNewTarget = CheckedUnwrapStatic(newTarget);
   3221    MOZ_ASSERT(unwrappedNewTarget);
   3222    MOZ_ASSERT(unwrappedNewTarget != newTarget);
   3223 
   3224    newTarget = unwrappedNewTarget;
   3225    {
   3226      AutoRealm ar(cx, newTarget);
   3227      Handle<GlobalObject*> global = cx->global();
   3228      JSObject* promiseCtor =
   3229          GlobalObject::getOrCreatePromiseConstructor(cx, global);
   3230      if (!promiseCtor) {
   3231        return false;
   3232      }
   3233 
   3234      // Promise subclasses don't get the special Xray treatment, so
   3235      // we only need to do the complex wrapping and unwrapping scheme
   3236      // described above for instances of Promise itself.
   3237      if (newTarget == promiseCtor) {
   3238        needsWrapping = true;
   3239        proto = GlobalObject::getOrCreatePromisePrototype(cx, cx->global());
   3240        if (!proto) {
   3241          return false;
   3242        }
   3243      }
   3244    }
   3245  }
   3246 
   3247  if (needsWrapping) {
   3248    if (!cx->compartment()->wrap(cx, &proto)) {
   3249      return false;
   3250    }
   3251  } else {
   3252    if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_Promise,
   3253                                            &proto)) {
   3254      return false;
   3255    }
   3256  }
   3257  PromiseObject* promise =
   3258      PromiseObject::create(cx, executor, proto, needsWrapping);
   3259  if (!promise) {
   3260    return false;
   3261  }
   3262 
   3263  // Step 11.
   3264  args.rval().setObject(*promise);
   3265  if (needsWrapping) {
   3266    return cx->compartment()->wrap(cx, args.rval());
   3267  }
   3268  return true;
   3269 }
   3270 
   3271 bool js::IsPromiseConstructor(const JSObject* obj) {
   3272  // Note: this also returns true for cross-realm Promise constructors in the
   3273  // same compartment.
   3274  return IsNativeFunction(obj, PromiseConstructor);
   3275 }
   3276 
   3277 /**
   3278 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   3279 *
   3280 * Promise ( executor )
   3281 * https://tc39.es/ecma262/#sec-promise-executor
   3282 *
   3283 * Steps 3-11.
   3284 */
   3285 /* static */
   3286 PromiseObject* PromiseObject::create(JSContext* cx, HandleObject executor,
   3287                                     HandleObject proto /* = nullptr */,
   3288                                     bool needsWrapping /* = false */) {
   3289  MOZ_ASSERT(executor->isCallable());
   3290 
   3291  RootedTuple<JSObject*, PromiseObject*, JSObject*, JSObject*, JSObject*,
   3292              JSObject*, Value, Value, SavedFrame*, Value>
   3293      roots(cx);
   3294  RootedField<JSObject*, 0> usedProto(roots, proto);
   3295  // If the proto is wrapped, that means the current function is running
   3296  // with a different compartment active from the one the Promise instance
   3297  // is to be created in.
   3298  // See the comment in PromiseConstructor for details.
   3299  if (needsWrapping) {
   3300    MOZ_ASSERT(proto);
   3301    usedProto = CheckedUnwrapStatic(proto);
   3302    if (!usedProto) {
   3303      ReportAccessDenied(cx);
   3304      return nullptr;
   3305    }
   3306  }
   3307 
   3308  // Steps 3-7.
   3309  RootedField<PromiseObject*, 1> promise(
   3310      roots, CreatePromiseObjectInternal(cx, usedProto, needsWrapping, false));
   3311  if (!promise) {
   3312    return nullptr;
   3313  }
   3314 
   3315  RootedField<JSObject*, 2> promiseObj(roots, promise);
   3316  if (needsWrapping && !cx->compartment()->wrap(cx, &promiseObj)) {
   3317    return nullptr;
   3318  }
   3319 
   3320  // Step 8. Let resolvingFunctions be CreateResolvingFunctions(promise).
   3321  //
   3322  // The resolving functions are created in the compartment active when the
   3323  // (maybe wrapped) Promise constructor was called. They contain checks and
   3324  // can unwrap the Promise if required.
   3325  RootedField<JSObject*, 3> resolveFn(roots);
   3326  RootedField<JSObject*, 4> rejectFn(roots);
   3327  if (!CreateResolvingFunctions(cx, promiseObj, &resolveFn, &rejectFn)) {
   3328    return nullptr;
   3329  }
   3330 
   3331  // Need to wrap the resolution functions before storing them on the Promise.
   3332  MOZ_ASSERT(promise->getFixedSlot(PromiseSlot_RejectFunction).isUndefined(),
   3333             "Slot must be undefined so initFixedSlot can be used");
   3334  if (needsWrapping) {
   3335    AutoRealm ar(cx, promise);
   3336    RootedField<JSObject*, 5> wrappedRejectFn(roots, rejectFn);
   3337    if (!cx->compartment()->wrap(cx, &wrappedRejectFn)) {
   3338      return nullptr;
   3339    }
   3340    promise->initFixedSlot(PromiseSlot_RejectFunction,
   3341                           ObjectValue(*wrappedRejectFn));
   3342  } else {
   3343    promise->initFixedSlot(PromiseSlot_RejectFunction, ObjectValue(*rejectFn));
   3344  }
   3345 
   3346  // Step 9. Let completion be
   3347  //         Call(executor, undefined, « resolvingFunctions.[[Resolve]],
   3348  //                                     resolvingFunctions.[[Reject]] »).
   3349  bool success;
   3350  {
   3351    FixedInvokeArgs<2> args(cx);
   3352    args[0].setObject(*resolveFn);
   3353    args[1].setObject(*rejectFn);
   3354 
   3355    RootedField<Value, 6> calleeOrRval(roots, ObjectValue(*executor));
   3356    success = Call(cx, calleeOrRval, UndefinedHandleValue, args, &calleeOrRval);
   3357  }
   3358 
   3359  // Step 10. If completion is an abrupt completion, then
   3360  if (!success) {
   3361    RootedField<Value, 7> exceptionVal(roots);
   3362    RootedField<SavedFrame*, 8> stack(roots);
   3363    if (!MaybeGetAndClearExceptionAndStack(cx, &exceptionVal, &stack)) {
   3364      return nullptr;
   3365    }
   3366 
   3367    // Step 10.a. Perform
   3368    //            ? Call(resolvingFunctions.[[Reject]], undefined,
   3369    //                   « completion.[[Value]] »).
   3370    RootedField<Value, 9> calleeOrRval(roots, ObjectValue(*rejectFn));
   3371    if (!Call(cx, calleeOrRval, UndefinedHandleValue, exceptionVal,
   3372              &calleeOrRval)) {
   3373      return nullptr;
   3374    }
   3375  }
   3376 
   3377  // Let the Debugger know about this Promise.
   3378  DebugAPI::onNewPromise(cx, promise);
   3379 
   3380  // Step 11. Return promise.
   3381  return promise;
   3382 }
   3383 
   3384 /**
   3385 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   3386 *
   3387 * Promise ( executor )
   3388 * https://tc39.es/ecma262/#sec-promise-executor
   3389 *
   3390 * skipping creation of resolution functions and executor function invocation.
   3391 */
   3392 /* static */
   3393 PromiseObject* PromiseObject::createSkippingExecutor(JSContext* cx) {
   3394  return CreatePromiseObjectWithoutResolutionFunctions(cx);
   3395 }
   3396 
   3397 class MOZ_STACK_CLASS PromiseForOfIterator : public JS::ForOfIterator {
   3398 public:
   3399  using JS::ForOfIterator::ForOfIterator;
   3400 
   3401  bool isOptimizedDenseArrayIteration() {
   3402    MOZ_ASSERT(valueIsIterable());
   3403    return index != NOT_ARRAY && IsPackedArray(iterator);
   3404  }
   3405 };
   3406 
   3407 [[nodiscard]] static bool PerformPromiseAll(
   3408    JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
   3409    Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
   3410    bool* done);
   3411 
   3412 [[nodiscard]] static bool PerformPromiseAllSettled(
   3413    JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
   3414    Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
   3415    bool* done);
   3416 
   3417 [[nodiscard]] static bool PerformPromiseAny(
   3418    JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
   3419    Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
   3420    bool* done);
   3421 
   3422 [[nodiscard]] static bool PerformPromiseRace(
   3423    JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
   3424    Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
   3425    bool* done);
   3426 
   3427 enum class CombinatorKind { All, AllSettled, Any, Race };
   3428 
   3429 /**
   3430 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   3431 *
   3432 * Unified implementation of
   3433 *
   3434 * Promise.all ( iterable )
   3435 * https://tc39.es/ecma262/#sec-promise.all
   3436 * Promise.allSettled ( iterable )
   3437 * https://tc39.es/ecma262/#sec-promise.allsettled
   3438 * Promise.race ( iterable )
   3439 * https://tc39.es/ecma262/#sec-promise.race
   3440 * Promise.any ( iterable )
   3441 * https://tc39.es/ecma262/#sec-promise.any
   3442 * GetPromiseResolve ( promiseConstructor )
   3443 * https://tc39.es/ecma262/#sec-getpromiseresolve
   3444 */
   3445 [[nodiscard]] static bool CommonPromiseCombinator(JSContext* cx, CallArgs& args,
   3446                                                  CombinatorKind kind) {
   3447  HandleValue iterable = args.get(0);
   3448 
   3449  // Step 2. Let promiseCapability be ? NewPromiseCapability(C).
   3450  // (moved from NewPromiseCapability, step 1).
   3451  HandleValue CVal = args.thisv();
   3452  if (!CVal.isObject()) {
   3453    const char* message;
   3454    switch (kind) {
   3455      case CombinatorKind::All:
   3456        message = "Receiver of Promise.all call";
   3457        break;
   3458      case CombinatorKind::AllSettled:
   3459        message = "Receiver of Promise.allSettled call";
   3460        break;
   3461      case CombinatorKind::Any:
   3462        message = "Receiver of Promise.any call";
   3463        break;
   3464      case CombinatorKind::Race:
   3465        message = "Receiver of Promise.race call";
   3466        break;
   3467    }
   3468    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   3469                              JSMSG_OBJECT_REQUIRED, message);
   3470    return false;
   3471  }
   3472 
   3473  // Step 1. Let C be the this value.
   3474  RootedObject C(cx, &CVal.toObject());
   3475 
   3476  // Step 2. Let promiseCapability be ? NewPromiseCapability(C).
   3477  Rooted<PromiseCapability> promiseCapability(cx);
   3478  if (!NewPromiseCapability(cx, C, &promiseCapability, false)) {
   3479    return false;
   3480  }
   3481 
   3482  RootedValue promiseResolve(cx, UndefinedValue());
   3483  {
   3484    JSObject* promiseCtor =
   3485        GlobalObject::getOrCreatePromiseConstructor(cx, cx->global());
   3486    if (!promiseCtor) {
   3487      return false;
   3488    }
   3489 
   3490    if (C != promiseCtor || !HasDefaultPromiseProperties(cx)) {
   3491      // Step 3. Let promiseResolve be GetPromiseResolve(C).
   3492 
   3493      // GetPromiseResolve
   3494      // Step 1. Let promiseResolve be ? Get(promiseConstructor, "resolve").
   3495      if (!GetProperty(cx, C, C, cx->names().resolve, &promiseResolve)) {
   3496        // Step 4. IfAbruptRejectPromise(promiseResolve, promiseCapability).
   3497        return AbruptRejectPromise(cx, args, promiseCapability);
   3498      }
   3499 
   3500      // GetPromiseResolve
   3501      // Step 2. If IsCallable(promiseResolve) is false,
   3502      //         throw a TypeError exception.
   3503      if (!IsCallable(promiseResolve)) {
   3504        ReportIsNotFunction(cx, promiseResolve);
   3505 
   3506        // Step 4. IfAbruptRejectPromise(promiseResolve, promiseCapability).
   3507        return AbruptRejectPromise(cx, args, promiseCapability);
   3508      }
   3509    }
   3510  }
   3511 
   3512  // Step 5. Let iteratorRecord be GetIterator(iterable).
   3513  PromiseForOfIterator iter(cx);
   3514  if (!iter.init(iterable, JS::ForOfIterator::AllowNonIterable)) {
   3515    // Step 6. IfAbruptRejectPromise(iteratorRecord, promiseCapability).
   3516    return AbruptRejectPromise(cx, args, promiseCapability);
   3517  }
   3518 
   3519  if (!iter.valueIsIterable()) {
   3520    // Step 6. IfAbruptRejectPromise(iteratorRecord, promiseCapability).
   3521    const char* message;
   3522    switch (kind) {
   3523      case CombinatorKind::All:
   3524        message = "Argument of Promise.all";
   3525        break;
   3526      case CombinatorKind::AllSettled:
   3527        message = "Argument of Promise.allSettled";
   3528        break;
   3529      case CombinatorKind::Any:
   3530        message = "Argument of Promise.any";
   3531        break;
   3532      case CombinatorKind::Race:
   3533        message = "Argument of Promise.race";
   3534        break;
   3535    }
   3536    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE,
   3537                              message);
   3538    return AbruptRejectPromise(cx, args, promiseCapability);
   3539  }
   3540 
   3541  bool done, result;
   3542  switch (kind) {
   3543    case CombinatorKind::All:
   3544      // Promise.all
   3545      // Step 7. Let result be
   3546      //         PerformPromiseAll(iteratorRecord, C, promiseCapability,
   3547      //                           promiseResolve).
   3548      result = PerformPromiseAll(cx, iter, C, promiseCapability, promiseResolve,
   3549                                 &done);
   3550      break;
   3551    case CombinatorKind::AllSettled:
   3552      // Promise.allSettled
   3553      // Step 7. Let result be
   3554      //         PerformPromiseAllSettled(iteratorRecord, C, promiseCapability,
   3555      //                                  promiseResolve).
   3556      result = PerformPromiseAllSettled(cx, iter, C, promiseCapability,
   3557                                        promiseResolve, &done);
   3558      break;
   3559    case CombinatorKind::Any:
   3560      // Promise.any
   3561      // Step 7. Let result be
   3562      //         PerformPromiseAny(iteratorRecord, C, promiseCapability,
   3563      //                           promiseResolve).
   3564      result = PerformPromiseAny(cx, iter, C, promiseCapability, promiseResolve,
   3565                                 &done);
   3566      break;
   3567    case CombinatorKind::Race:
   3568      // Promise.race
   3569      // Step 7. Let result be
   3570      //         PerformPromiseRace(iteratorRecord, C, promiseCapability,
   3571      //                            promiseResolve).
   3572      result = PerformPromiseRace(cx, iter, C, promiseCapability,
   3573                                  promiseResolve, &done);
   3574      break;
   3575  }
   3576 
   3577  // Step 8. If result is an abrupt completion, then
   3578  if (!result) {
   3579    // Step 8.a. If iteratorRecord.[[Done]] is false,
   3580    //           set result to IteratorClose(iteratorRecord, result).
   3581    if (!done) {
   3582      iter.closeThrow();
   3583    }
   3584 
   3585    // Step 8.b. IfAbruptRejectPromise(result, promiseCapability).
   3586    return AbruptRejectPromise(cx, args, promiseCapability);
   3587  }
   3588 
   3589  // Step 9. Return Completion(result).
   3590  args.rval().setObject(*promiseCapability.promise());
   3591  return true;
   3592 }
   3593 
   3594 /**
   3595 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   3596 *
   3597 * Promise.all ( iterable )
   3598 * https://tc39.es/ecma262/#sec-promise.all
   3599 */
   3600 static bool Promise_static_all(JSContext* cx, unsigned argc, Value* vp) {
   3601  CallArgs args = CallArgsFromVp(argc, vp);
   3602  return CommonPromiseCombinator(cx, args, CombinatorKind::All);
   3603 }
   3604 
   3605 #ifdef NIGHTLY_BUILD
   3606 /**
   3607 * Await Dictionary Proposal
   3608 *
   3609 * Promise.allKeyed
   3610 * https://tc39.es/proposal-await-dictionary/#sec-promise.allkeyed
   3611 */
   3612 static bool Promise_static_allKeyed(JSContext* cx, unsigned argc, Value* vp) {
   3613  JS_ReportErrorASCII(cx, "Promise.allKeyed is not yet implemented");
   3614  return false;
   3615 }
   3616 
   3617 /**
   3618 * Await Dictionary Proposal
   3619 *
   3620 * Promise.allSettledKeyed
   3621 * https://tc39.es/proposal-await-dictionary/#sec-promise.allsettledkeyed
   3622 */
   3623 static bool Promise_static_allSettledKeyed(JSContext* cx, unsigned argc,
   3624                                           Value* vp) {
   3625  JS_ReportErrorASCII(cx, "Promise.allSettledKeyed is not yet implemented");
   3626  return false;
   3627 }
   3628 #endif
   3629 
   3630 [[nodiscard]] static bool PerformPromiseThen(
   3631    JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled_,
   3632    HandleValue onRejected_, Handle<PromiseCapability> resultCapability);
   3633 
   3634 [[nodiscard]] static bool PerformPromiseThenWithoutSettleHandlers(
   3635    JSContext* cx, Handle<PromiseObject*> promise,
   3636    Handle<PromiseObject*> promiseToResolve,
   3637    Handle<PromiseCapability> resultCapability);
   3638 
   3639 static JSFunction* NewPromiseCombinatorElementFunction(
   3640    JSContext* cx, Native native,
   3641    Handle<PromiseCombinatorDataHolder*> dataHolder, uint32_t index,
   3642    Handle<Value> maybeResolveFunc);
   3643 
   3644 static bool PromiseAllResolveElementFunction(JSContext* cx, unsigned argc,
   3645                                             Value* vp);
   3646 
   3647 /**
   3648 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   3649 *
   3650 * Promise.all ( iterable )
   3651 * https://tc39.es/ecma262/#sec-promise.all
   3652 * PerformPromiseAll ( iteratorRecord, constructor, resultCapability,
   3653 *                     promiseResolve )
   3654 * https://tc39.es/ecma262/#sec-performpromiseall
   3655 *
   3656 * Unforgeable version.
   3657 */
   3658 [[nodiscard]] JSObject* js::GetWaitForAllPromise(
   3659    JSContext* cx, JS::HandleObjectVector promises) {
   3660 #ifdef DEBUG
   3661  for (size_t i = 0, len = promises.length(); i < len; i++) {
   3662    JSObject* obj = promises[i];
   3663    cx->check(obj);
   3664    JSObject* unwrapped = UncheckedUnwrap(obj);
   3665    MOZ_ASSERT(unwrapped->is<PromiseObject>() || JS_IsDeadWrapper(unwrapped));
   3666  }
   3667 #endif
   3668 
   3669  // Step 1. Let C be the this value.
   3670  RootedObject C(cx,
   3671                 GlobalObject::getOrCreatePromiseConstructor(cx, cx->global()));
   3672  if (!C) {
   3673    return nullptr;
   3674  }
   3675 
   3676  // Step 2. Let promiseCapability be ? NewPromiseCapability(C).
   3677  Rooted<PromiseCapability> resultCapability(cx);
   3678  if (!NewPromiseCapability(cx, C, &resultCapability, false)) {
   3679    return nullptr;
   3680  }
   3681 
   3682  // Steps 3-6 for iterator and iteratorRecord.
   3683  // (omitted)
   3684 
   3685  // Step 7. Let result be
   3686  //         PerformPromiseAll(iteratorRecord, C, promiseCapability,
   3687  //                           promiseResolve).
   3688  //
   3689  // Implemented as an inlined, simplied version of PerformPromiseAll.
   3690  {
   3691    uint32_t promiseCount = promises.length();
   3692    // PerformPromiseAll
   3693 
   3694    // Step 1. Let values be a new empty List.
   3695    Rooted<PromiseCombinatorElements> values(cx);
   3696    {
   3697      auto* valuesArray = NewDenseFullyAllocatedArray(cx, promiseCount);
   3698      if (!valuesArray) {
   3699        return nullptr;
   3700      }
   3701      valuesArray->ensureDenseInitializedLength(0, promiseCount);
   3702 
   3703      values.initialize(valuesArray);
   3704    }
   3705 
   3706    // Step 2. Let remainingElementsCount be the Record { [[Value]]: 1 }.
   3707    //
   3708    // Create our data holder that holds all the things shared across
   3709    // every step of the iterator.  In particular, this holds the
   3710    // remainingElementsCount (as an integer reserved slot), the array of
   3711    // values, and the resolve function from our PromiseCapability.
   3712    Rooted<PromiseCombinatorDataHolder*> dataHolder(cx);
   3713    dataHolder = PromiseCombinatorDataHolder::New(
   3714        cx, resultCapability.promise(), values, resultCapability.resolve());
   3715    if (!dataHolder) {
   3716      return nullptr;
   3717    }
   3718 
   3719    // Call PerformPromiseThen with resolve and reject set to nullptr.
   3720    Rooted<PromiseCapability> resultCapabilityWithoutResolving(cx);
   3721    resultCapabilityWithoutResolving.promise().set(resultCapability.promise());
   3722 
   3723    // Step 3. Let index be 0.
   3724    // Step 4. Repeat,
   3725    // Step 4.t. Set index to index + 1.
   3726    for (uint32_t index = 0; index < promiseCount; index++) {
   3727      // Steps 4.a-c for IteratorStep.
   3728      // (omitted)
   3729 
   3730      // Step 4.d. (implemented after the loop).
   3731 
   3732      // Steps 4.e-g for IteratorValue
   3733      // (omitted)
   3734 
   3735      // Step 4.h. Append undefined to values.
   3736      values.unwrappedArray()->setDenseElement(index, UndefinedHandleValue);
   3737 
   3738      // Step 4.i. Let nextPromise be
   3739      //           ? Call(promiseResolve, constructor, « nextValue »).
   3740      RootedObject nextPromiseObj(cx, promises[index]);
   3741 
   3742      // Steps 4.j-q.
   3743      JSFunction* resolveFunc = NewPromiseCombinatorElementFunction(
   3744          cx, PromiseAllResolveElementFunction, dataHolder, index,
   3745          UndefinedHandleValue);
   3746      if (!resolveFunc) {
   3747        return nullptr;
   3748      }
   3749 
   3750      // Step 4.r. Set remainingElementsCount.[[Value]] to
   3751      //           remainingElementsCount.[[Value]] + 1.
   3752      dataHolder->increaseRemainingCount();
   3753 
   3754      // Step 4.s. Perform
   3755      //           ? Invoke(nextPromise, "then",
   3756      //                    « onFulfilled, resultCapability.[[Reject]] »).
   3757      RootedValue resolveFunVal(cx, ObjectValue(*resolveFunc));
   3758      RootedValue rejectFunVal(cx, ObjectValue(*resultCapability.reject()));
   3759      Rooted<PromiseObject*> nextPromise(cx);
   3760 
   3761      // GetWaitForAllPromise is used internally only and must not
   3762      // trigger content-observable effects when registering a reaction.
   3763      // It's also meant to work on wrapped Promises, potentially from
   3764      // compartments with principals inaccessible from the current
   3765      // compartment. To make that work, it unwraps promises with
   3766      // UncheckedUnwrap,
   3767      JSObject* unwrapped = UncheckedUnwrap(nextPromiseObj);
   3768      if (JS_IsDeadWrapper(unwrapped)) {
   3769        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   3770                                  JSMSG_DEAD_OBJECT);
   3771        return nullptr;
   3772      }
   3773      nextPromise = &unwrapped->as<PromiseObject>();
   3774 
   3775      if (!PerformPromiseThen(cx, nextPromise, resolveFunVal, rejectFunVal,
   3776                              resultCapabilityWithoutResolving)) {
   3777        return nullptr;
   3778      }
   3779    }
   3780 
   3781    // Step 4.d.i. Set iteratorRecord.[[Done]] to true.
   3782    // (implicit)
   3783 
   3784    // Step 4.d.ii. Set remainingElementsCount.[[Value]] to
   3785    //              remainingElementsCount.[[Value]] - 1.
   3786    int32_t remainingCount = dataHolder->decreaseRemainingCount();
   3787 
   3788    // Step 4.d.iii.If remainingElementsCount.[[Value]] is 0, then
   3789    if (remainingCount == 0) {
   3790      // Step 4.d.iii.1. Let valuesArray be ! CreateArrayFromList(values).
   3791      // (already performed)
   3792 
   3793      // Step 4.d.iii.2. Perform
   3794      //                 ? Call(resultCapability.[[Resolve]], undefined,
   3795      //                        « valuesArray »).
   3796      if (!ResolvePromiseInternal(cx, resultCapability.promise(),
   3797                                  values.value())) {
   3798        return nullptr;
   3799      }
   3800    }
   3801  }
   3802 
   3803  // Step 4.d.iv. Return resultCapability.[[Promise]].
   3804  return resultCapability.promise();
   3805 }
   3806 
   3807 static bool CallDefaultPromiseResolveFunction(JSContext* cx,
   3808                                              Handle<PromiseObject*> promise,
   3809                                              HandleValue resolutionValue);
   3810 static bool CallDefaultPromiseRejectFunction(
   3811    JSContext* cx, Handle<PromiseObject*> promise, HandleValue rejectionValue,
   3812    JS::Handle<SavedFrame*> unwrappedRejectionStack = nullptr);
   3813 
   3814 /**
   3815 * Perform Call(promiseCapability.[[Resolve]], undefined ,« value ») given
   3816 * promiseCapability = { promiseObj, resolveFun }.
   3817 *
   3818 * Also,
   3819 *
   3820 * ES2023 draft rev 714fa3dd1e8237ae9c666146270f81880089eca5
   3821 *
   3822 * NewPromiseReactionJob ( reaction, argument )
   3823 * https://tc39.es/ecma262/#sec-newpromisereactionjob
   3824 *
   3825 * Steps 1.f-i. "type is Fulfill" case.
   3826 */
   3827 [[nodiscard]] static bool CallPromiseResolveFunction(JSContext* cx,
   3828                                                     HandleObject resolveFun,
   3829                                                     HandleValue value,
   3830                                                     HandleObject promiseObj) {
   3831  cx->check(resolveFun, value, promiseObj);
   3832 
   3833  // NewPromiseReactionJob
   3834  // Step 1.g. Assert: promiseCapability is a PromiseCapability Record.
   3835  // (implicit)
   3836 
   3837  if (resolveFun) {
   3838    // NewPromiseReactionJob
   3839    // Step 1.h. If handlerResult is an abrupt completion, then
   3840    //           (handled in CallPromiseRejectFunction)
   3841    // Step 1.i. Else,
   3842    // Step 1.i.i. Return
   3843    //             ? Call(promiseCapability.[[Resolve]], undefined,
   3844    //                    « handlerResult.[[Value]] »).
   3845    RootedValue calleeOrRval(cx, ObjectValue(*resolveFun));
   3846    return Call(cx, calleeOrRval, UndefinedHandleValue, value, &calleeOrRval);
   3847  }
   3848 
   3849  // `promiseObj` can be optimized away if it's known to be unused.
   3850  //
   3851  // NewPromiseReactionJob
   3852  // Step f. If promiseCapability is undefined, then
   3853  // (reordered)
   3854  //
   3855  // NOTE: "promiseCapability is undefined" case is represented by
   3856  //       `resolveFun == nullptr && promiseObj == nullptr`.
   3857  if (!promiseObj) {
   3858    // NewPromiseReactionJob
   3859    // Step f.i. Assert: handlerResult is not an abrupt completion.
   3860    // (implicit)
   3861 
   3862    // Step f.ii. Return empty.
   3863    return true;
   3864  }
   3865 
   3866  // NewPromiseReactionJob
   3867  // Step 1.h. If handlerResult is an abrupt completion, then
   3868  //           (handled in CallPromiseRejectFunction)
   3869  // Step 1.i. Else,
   3870  // Step 1.i.i. Return
   3871  //             ? Call(promiseCapability.[[Resolve]], undefined,
   3872  //                    « handlerResult.[[Value]] »).
   3873  Handle<PromiseObject*> promise = promiseObj.as<PromiseObject>();
   3874  if (IsPromiseWithDefaultResolvingFunction(promise)) {
   3875    return CallDefaultPromiseResolveFunction(cx, promise, value);
   3876  }
   3877 
   3878  // This case is used by resultCapabilityWithoutResolving in
   3879  // GetWaitForAllPromise, and nothing should be done.
   3880 
   3881  return true;
   3882 }
   3883 
   3884 /**
   3885 * Perform Call(promiseCapability.[[Reject]], undefined ,« reason ») given
   3886 * promiseCapability = { promiseObj, rejectFun }.
   3887 *
   3888 * Also,
   3889 *
   3890 * ES2023 draft rev 714fa3dd1e8237ae9c666146270f81880089eca5
   3891 *
   3892 * NewPromiseReactionJob ( reaction, argument )
   3893 * https://tc39.es/ecma262/#sec-newpromisereactionjob
   3894 *
   3895 * Steps 1.g-i. "type is Reject" case.
   3896 */
   3897 [[nodiscard]] static bool CallPromiseRejectFunction(
   3898    JSContext* cx, HandleObject rejectFun, HandleValue reason,
   3899    HandleObject promiseObj, Handle<SavedFrame*> unwrappedRejectionStack,
   3900    UnhandledRejectionBehavior behavior) {
   3901  cx->check(rejectFun, reason, promiseObj);
   3902 
   3903  // NewPromiseReactionJob
   3904  // Step 1.g. Assert: promiseCapability is a PromiseCapability Record.
   3905  // (implicit)
   3906 
   3907  if (rejectFun) {
   3908    // NewPromiseReactionJob
   3909    // Step 1.h. If handlerResult is an abrupt completion, then
   3910    // Step 1.h.i. Return
   3911    //             ? Call(promiseCapability.[[Reject]], undefined,
   3912    //                    « handlerResult.[[Value]] »).
   3913    RootedValue calleeOrRval(cx, ObjectValue(*rejectFun));
   3914    return Call(cx, calleeOrRval, UndefinedHandleValue, reason, &calleeOrRval);
   3915  }
   3916 
   3917  // NewPromiseReactionJob
   3918  // See the comment in CallPromiseResolveFunction for promiseCapability field
   3919  //
   3920  // Step f. If promiseCapability is undefined, then
   3921  // Step f.i. Assert: handlerResult is not an abrupt completion.
   3922  //
   3923  // The spec doesn't allow promiseCapability to be undefined for reject case,
   3924  // but `promiseObj` can be optimized away if it's known to be unused.
   3925  if (!promiseObj) {
   3926    if (behavior == UnhandledRejectionBehavior::Ignore) {
   3927      // Do nothing if unhandled rejections are to be ignored.
   3928      return true;
   3929    }
   3930 
   3931    // Otherwise create and reject a promise on the fly.  The promise's
   3932    // allocation time will be wrong.  So it goes.
   3933    Rooted<PromiseObject*> temporaryPromise(
   3934        cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
   3935    if (!temporaryPromise) {
   3936      cx->clearPendingException();
   3937      return true;
   3938    }
   3939 
   3940    // NewPromiseReactionJob
   3941    // Step 1.h. If handlerResult is an abrupt completion, then
   3942    // Step 1.h.i. Return
   3943    //             ? Call(promiseCapability.[[Reject]], undefined,
   3944    //                    « handlerResult.[[Value]] »).
   3945    return RejectPromiseInternal(cx, temporaryPromise, reason,
   3946                                 unwrappedRejectionStack);
   3947  }
   3948 
   3949  // NewPromiseReactionJob
   3950  // Step 1.h. If handlerResult is an abrupt completion, then
   3951  // Step 1.h.i. Return
   3952  //             ? Call(promiseCapability.[[Reject]], undefined,
   3953  //                    « handlerResult.[[Value]] »).
   3954  Handle<PromiseObject*> promise = promiseObj.as<PromiseObject>();
   3955  if (IsPromiseWithDefaultResolvingFunction(promise)) {
   3956    return CallDefaultPromiseRejectFunction(cx, promise, reason,
   3957                                            unwrappedRejectionStack);
   3958  }
   3959 
   3960  // This case is used by resultCapabilityWithoutResolving in
   3961  // GetWaitForAllPromise, and nothing should be done.
   3962 
   3963  return true;
   3964 }
   3965 
   3966 [[nodiscard]] static JSObject* CommonStaticResolveRejectImpl(
   3967    JSContext* cx, HandleValue thisVal, HandleValue argVal,
   3968    ResolutionMode mode);
   3969 
   3970 static bool IsPromiseSpecies(JSContext* cx, JSFunction* species);
   3971 
   3972 /**
   3973 * ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
   3974 *
   3975 * Unified implementation of
   3976 *
   3977 * PerformPromiseAll ( iteratorRecord, constructor, resultCapability,
   3978 *                     promiseResolve )
   3979 * https://tc39.es/ecma262/#sec-performpromiseall
   3980 * PerformPromiseAllSettled ( iteratorRecord, constructor, resultCapability,
   3981 *                            promiseResolve )
   3982 * https://tc39.es/ecma262/#sec-performpromiseallsettled
   3983 * PerformPromiseRace ( iteratorRecord, constructor, resultCapability,
   3984 *                      promiseResolve )
   3985 * https://tc39.es/ecma262/#sec-performpromiserace
   3986 * PerformPromiseAny ( iteratorRecord, constructor, resultCapability,
   3987 *                     promiseResolve )
   3988 * https://tc39.es/ecma262/#sec-performpromiseany
   3989 *
   3990 * Promise.prototype.then ( onFulfilled, onRejected )
   3991 * https://tc39.es/ecma262/#sec-promise.prototype.then
   3992 */
   3993 template <typename T>
   3994 [[nodiscard]] static bool CommonPerformPromiseCombinator(
   3995    JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
   3996    HandleObject resultPromise, HandleValue promiseResolve, bool* done,
   3997    bool resolveReturnsUndefined, T getResolveAndReject) {
   3998  RootedObject promiseCtor(
   3999      cx, GlobalObject::getOrCreatePromiseConstructor(cx, cx->global()));
   4000  if (!promiseCtor) {
   4001    return false;
   4002  }
   4003 
   4004  // Optimized dense array iteration ensures no side-effects take place
   4005  // during the iteration.
   4006  bool iterationMayHaveSideEffects = !iterator.isOptimizedDenseArrayIteration();
   4007 
   4008  // Try to optimize when the Promise object is in its default state, guarded
   4009  // by |C == promiseCtor| because we can only perform this optimization
   4010  // for the builtin Promise constructor.
   4011  bool isDefaultPromiseState =
   4012      C == promiseCtor && HasDefaultPromiseProperties(cx);
   4013  bool validatePromiseState = iterationMayHaveSideEffects;
   4014 
   4015  RootedValue CVal(cx, ObjectValue(*C));
   4016  RootedValue resolveFunVal(cx);
   4017  RootedValue rejectFunVal(cx);
   4018 
   4019  // We're reusing rooted variables in the loop below, so we don't need to
   4020  // declare a gazillion different rooted variables here. Rooted variables
   4021  // which are reused include "Or" in their name.
   4022  RootedValue nextValueOrNextPromise(cx);
   4023  RootedObject nextPromiseObj(cx);
   4024  RootedValue thenVal(cx);
   4025  RootedObject thenSpeciesOrBlockedPromise(cx);
   4026  Rooted<PromiseCapability> thenCapability(cx);
   4027 
   4028  // PerformPromiseAll, PerformPromiseAllSettled, PerformPromiseAny
   4029  // Step 4.
   4030  // PerformPromiseRace
   4031  // Step 1.
   4032  while (true) {
   4033    // Step a. Let next be ? IteratorStepValue(iteratorRecord).
   4034    RootedValue& nextValue = nextValueOrNextPromise;
   4035    if (!iterator.next(&nextValue, done)) {
   4036      *done = true;
   4037      return false;
   4038    }
   4039 
   4040    // Step b. If next is done, then
   4041    if (*done) {
   4042      return true;
   4043    }
   4044 
   4045    // Set to false when we can skip the [[Get]] for "then" and instead
   4046    // use the built-in Promise.prototype.then function.
   4047    bool getThen = true;
   4048 
   4049    if (isDefaultPromiseState && validatePromiseState) {
   4050      isDefaultPromiseState = HasDefaultPromiseProperties(cx);
   4051    }
   4052 
   4053    RootedValue& nextPromise = nextValueOrNextPromise;
   4054    if (isDefaultPromiseState) {
   4055      PromiseObject* nextValuePromise = nullptr;
   4056      if (nextValue.isObject() && nextValue.toObject().is<PromiseObject>()) {
   4057        nextValuePromise = &nextValue.toObject().as<PromiseObject>();
   4058      }
   4059 
   4060      if (nextValuePromise &&
   4061          IsPromiseWithDefaultProperties(nextValuePromise, cx)) {
   4062        // The below steps don't produce any side-effects, so we can
   4063        // skip the Promise state revalidation in the next iteration
   4064        // when the iterator itself also doesn't produce any
   4065        // side-effects.
   4066        validatePromiseState = iterationMayHaveSideEffects;
   4067 
   4068        // Step {c, d}. Let nextPromise be
   4069        //              ? Call(promiseResolve, constructor, « next »).
   4070        // Promise.resolve is a no-op for the default case.
   4071        MOZ_ASSERT(&nextPromise.toObject() == nextValuePromise);
   4072 
   4073        // `nextPromise` uses the built-in `then` function.
   4074        getThen = false;
   4075      } else {
   4076        // Need to revalidate the Promise state in the next iteration,
   4077        // because CommonStaticResolveRejectImpl may have modified it.
   4078        validatePromiseState = true;
   4079 
   4080        // Step {c, d}. Let nextPromise be
   4081        //              ? Call(promiseResolve, constructor, « next »).
   4082        // Inline the call to Promise.resolve.
   4083        JSObject* res =
   4084            CommonStaticResolveRejectImpl(cx, CVal, nextValue, ResolveMode);
   4085        if (!res) {
   4086          return false;
   4087        }
   4088 
   4089        nextPromise.setObject(*res);
   4090      }
   4091    } else if (promiseResolve.isUndefined()) {
   4092      // |promiseResolve| is undefined when the Promise constructor was
   4093      // initially in its default state, i.e. if it had been retrieved, it would
   4094      // have been set to |Promise.resolve|.
   4095 
   4096      // Step {c, d}. Let nextPromise be
   4097      //              ? Call(promiseResolve, constructor, « next »).
   4098      // Inline the call to Promise.resolve.
   4099      JSObject* res =
   4100          CommonStaticResolveRejectImpl(cx, CVal, nextValue, ResolveMode);
   4101      if (!res) {
   4102        return false;
   4103      }
   4104 
   4105      nextPromise.setObject(*res);
   4106    } else {
   4107      // Step {c, d}. Let nextPromise be
   4108      //              ? Call(promiseResolve, constructor, « next »).
   4109      if (!Call(cx, promiseResolve, CVal, nextValue, &nextPromise)) {
   4110        return false;
   4111      }
   4112    }
   4113 
   4114    // Get the resolving functions for this iteration.
   4115    // PerformPromiseAll
   4116    // Steps c and e-m.
   4117    // PerformPromiseAllSettled
   4118    // Steps c and e-v.
   4119    // PerformPromiseAny
   4120    // Steps c and e-m.
   4121    if (!getResolveAndReject(&resolveFunVal, &rejectFunVal)) {
   4122      return false;
   4123    }
   4124 
   4125    // Call |nextPromise.then| with the provided hooks and add
   4126    // |resultPromise| to the list of dependent promises.
   4127    //
   4128    // If |nextPromise.then| is the original |Promise.prototype.then|
   4129    // function and the call to |nextPromise.then| would use the original
   4130    // |Promise| constructor to create the resulting promise, we skip the
   4131    // call to |nextPromise.then| and thus creating a new promise that
   4132    // would not be observable by content.
   4133 
   4134    // PerformPromiseAll
   4135    // Step n. Perform
   4136    //         ? Invoke(nextPromise, "then",
   4137    //                  « onFulfilled, resultCapability.[[Reject]] »).
   4138    // PerformPromiseAllSettled
   4139    // Step w. Perform
   4140    //         ? Invoke(nextPromise, "then", « onFulfilled, onRejected »).
   4141    // PerformPromiseRace
   4142    // Step d. Perform
   4143    //         ? Invoke(nextPromise, "then",
   4144    //                  « resultCapability.[[Resolve]],
   4145    //                    resultCapability.[[Reject]] »).
   4146    // PerformPromiseAny
   4147    // Step n. Perform
   4148    //         ? Invoke(nextPromise, "then",
   4149    //                  « resultCapability.[[Resolve]], onRejected »).
   4150    nextPromiseObj = ToObject(cx, nextPromise);
   4151    if (!nextPromiseObj) {
   4152      return false;
   4153    }
   4154 
   4155    bool isBuiltinThen;
   4156    bool isOnProto = false;
   4157    bool isOnStandardProto = false;
   4158    bool isOnObjectProto = false;
   4159    if (getThen) {
   4160      // We don't use the Promise lookup cache here, because this code
   4161      // is only called when we had a lookup cache miss, so it's likely
   4162      // we'd get another cache miss when trying to use the cache here.
   4163      if (!GetThenValue(cx, nextPromiseObj, nextPromise, &thenVal, &isOnProto,
   4164                        &isOnStandardProto, &isOnObjectProto)) {
   4165        return false;
   4166      }
   4167 
   4168      // |nextPromise| is an unwrapped Promise, and |then| is the
   4169      // original |Promise.prototype.then|, inline it here.
   4170      isBuiltinThen = nextPromiseObj->is<PromiseObject>() &&
   4171                      IsNativeFunction(thenVal, Promise_then);
   4172    } else {
   4173      isBuiltinThen = true;
   4174    }
   4175 
   4176    // By default, the blocked promise is added as an extra entry to the
   4177    // rejected promises list.
   4178    bool addToDependent = true;
   4179 
   4180    if (isBuiltinThen) {
   4181      MOZ_ASSERT(nextPromise.isObject());
   4182      MOZ_ASSERT(&nextPromise.toObject() == nextPromiseObj);
   4183 
   4184      // Promise.prototype.then
   4185      // Step 3. Let C be ? SpeciesConstructor(promise, %Promise%).
   4186      RootedObject& thenSpecies = thenSpeciesOrBlockedPromise;
   4187      if (getThen) {
   4188        thenSpecies = SpeciesConstructor(cx, nextPromiseObj, JSProto_Promise,
   4189                                         IsPromiseSpecies);
   4190        if (!thenSpecies) {
   4191          return false;
   4192        }
   4193      } else {
   4194        thenSpecies = promiseCtor;
   4195      }
   4196 
   4197      // The fast path here and the one in NewPromiseCapability may not
   4198      // set the resolve and reject handlers, so we need to clear the
   4199      // fields in case they were set in the previous iteration.
   4200      thenCapability.resolve().set(nullptr);
   4201      thenCapability.reject().set(nullptr);
   4202 
   4203      // Skip the creation of a built-in Promise object if:
   4204      // 1. `thenSpecies` is the built-in Promise constructor.
   4205      // 2. `resolveFun` doesn't return an object, which ensures no side effects
   4206      //    occur in ResolvePromiseInternal.
   4207      // 3. The result promise is a built-in Promise object.
   4208      // 4. The result promise doesn't use the default resolving functions,
   4209      //    which in turn means Run{Fulfill,Reject}Function when called from
   4210      //    PromiseReactionJob won't try to resolve the promise.
   4211      if (thenSpecies == promiseCtor && resolveReturnsUndefined &&
   4212          resultPromise->is<PromiseObject>() &&
   4213          !IsPromiseWithDefaultResolvingFunction(
   4214              &resultPromise->as<PromiseObject>())) {
   4215        thenCapability.promise().set(resultPromise);
   4216        addToDependent = false;
   4217      } else {
   4218        // Promise.prototype.then
   4219        // Step 4. Let resultCapability be ? NewPromiseCapability(C).
   4220        if (!NewPromiseCapability(cx, thenSpecies, &thenCapability, true)) {
   4221          return false;
   4222        }
   4223      }
   4224 
   4225      // Promise.prototype.then
   4226      // Step 5. Return
   4227      //         PerformPromiseThen(promise, onFulfilled, onRejected,
   4228      //                            resultCapability).
   4229      Handle<PromiseObject*> promise = nextPromiseObj.as<PromiseObject>();
   4230      if (!PerformPromiseThen(cx, promise, resolveFunVal, rejectFunVal,
   4231                              thenCapability)) {
   4232        return false;
   4233      }
   4234    } else {
   4235      ReportThenable(cx, isOnProto, isOnStandardProto, isOnObjectProto);
   4236 
   4237      RootedValue& ignored = thenVal;
   4238      if (!Call(cx, thenVal, nextPromise, resolveFunVal, rejectFunVal,
   4239                &ignored)) {
   4240        return false;
   4241      }
   4242 
   4243      // In case the value to depend on isn't an object at all, there's
   4244      // nothing more to do here: we can only add reactions to Promise
   4245      // objects (potentially after unwrapping them), and non-object
   4246      // values can't be Promise objects. This can happen if Promise.all
   4247      // is called on an object with a `resolve` method that returns
   4248      // primitives.
   4249      if (!nextPromise.isObject()) {
   4250        addToDependent = false;
   4251      }
   4252    }
   4253 
   4254    // Adds |resultPromise| to the list of dependent promises.
   4255    if (addToDependent) {
   4256      // The object created by the |promise.then| call or the inlined
   4257      // version of it above is visible to content (either because
   4258      // |promise.then| was overridden by content and could leak it,
   4259      // or because a constructor other than the original value of
   4260      // |Promise| was used to create it). To have both that object and
   4261      // |resultPromise| show up as dependent promises in the debugger,
   4262      // add a dummy reaction to the list of reject reactions that
   4263      // contains |resultPromise|, but otherwise does nothing.
   4264      RootedObject& blockedPromise = thenSpeciesOrBlockedPromise;
   4265      blockedPromise = resultPromise;
   4266 
   4267      mozilla::Maybe<AutoRealm> ar;
   4268      if (IsProxy(nextPromiseObj)) {
   4269        nextPromiseObj = CheckedUnwrapStatic(nextPromiseObj);
   4270        if (!nextPromiseObj) {
   4271          ReportAccessDenied(cx);
   4272          return false;
   4273        }
   4274        if (JS_IsDeadWrapper(nextPromiseObj)) {
   4275          JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   4276                                    JSMSG_DEAD_OBJECT);
   4277          return false;
   4278        }
   4279        ar.emplace(cx, nextPromiseObj);
   4280        if (!cx->compartment()->wrap(cx, &blockedPromise)) {
   4281          return false;
   4282        }
   4283      }
   4284 
   4285      // If either the object to depend on (`nextPromiseObj`) or the
   4286      // object that gets blocked (`resultPromise`) isn't a,
   4287      // maybe-wrapped, Promise instance, we ignore it. All this does is
   4288      // lose some small amount of debug information in scenarios that
   4289      // are highly unlikely to occur in useful code.
   4290      if (nextPromiseObj->is<PromiseObject>() &&
   4291          resultPromise->is<PromiseObject>()) {
   4292        Handle<PromiseObject*> promise = nextPromiseObj.as<PromiseObject>();
   4293        if (!AddDummyPromiseReactionForDebugger(cx, promise, blockedPromise)) {
   4294          return false;
   4295        }
   4296      }
   4297    }
   4298  }
   4299 }
   4300 
   4301 // Create the elements for the Promise combinators Promise.all and
   4302 // Promise.allSettled.
   4303 // Create the errors list for the Promise combinator Promise.any.
   4304 [[nodiscard]] static bool NewPromiseCombinatorElements(
   4305    JSContext* cx, Handle<PromiseCapability> resultCapability,
   4306    MutableHandle<PromiseCombinatorElements> elements) {
   4307  // We have to be very careful about which compartments we create things for
   4308  // the Promise combinators. In particular, we have to maintain the invariant
   4309  // that anything stored in a reserved slot is same-compartment with the object
   4310  // whose reserved slot it's in. But we want to create the values array in the
   4311  // compartment of the result capability's Promise, because that array can get
   4312  // exposed as the Promise's resolution value to code that has access to the
   4313  // Promise (in particular code from that compartment), and that should work,
   4314  // even if the Promise compartment is less-privileged than our caller
   4315  // compartment.
   4316  //
   4317  // So the plan is as follows: Create the values array in the promise
   4318  // compartment. Create the promise resolving functions and the data holder in
   4319  // our current compartment, i.e. the compartment of the Promise combinator
   4320  // function. Store a cross-compartment wrapper to the values array in the
   4321  // holder. This should be OK because the only things we hand the promise
   4322  // resolving functions to are the "then" calls we do and in the case when the
   4323  // Promise's compartment is not the current compartment those are happening
   4324  // over Xrays anyway, which means they get the canonical "then" function and
   4325  // content can't see our promise resolving functions.
   4326 
   4327  if (IsWrapper(resultCapability.promise())) {
   4328    JSObject* unwrappedPromiseObj =
   4329        CheckedUnwrapStatic(resultCapability.promise());
   4330    MOZ_ASSERT(unwrappedPromiseObj);
   4331 
   4332    {
   4333      AutoRealm ar(cx, unwrappedPromiseObj);
   4334      auto* array = NewDenseEmptyArray(cx);
   4335      if (!array) {
   4336        return false;
   4337      }
   4338      elements.initialize(array);
   4339    }
   4340 
   4341    if (!cx->compartment()->wrap(cx, elements.value())) {
   4342      return false;
   4343    }
   4344  } else {
   4345    auto* array = NewDenseEmptyArray(cx);
   4346    if (!array) {
   4347      return false;
   4348    }
   4349 
   4350    elements.initialize(array);
   4351  }
   4352  return true;
   4353 }
   4354 
   4355 // Retrieve the combinator elements from the data holder.
   4356 [[nodiscard]] static bool GetPromiseCombinatorElements(
   4357    JSContext* cx, Handle<PromiseCombinatorDataHolder*> data,
   4358    MutableHandle<PromiseCombinatorElements> elements) {
   4359  bool needsWrapping = false;
   4360  JSObject* valuesObj = &data->valuesArray().toObject();
   4361  if (IsProxy(valuesObj)) {
   4362    // See comment for NewPromiseCombinatorElements for why we unwrap here.
   4363    valuesObj = UncheckedUnwrap(valuesObj);
   4364 
   4365    if (JS_IsDeadWrapper(valuesObj)) {
   4366      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   4367                                JSMSG_DEAD_OBJECT);
   4368      return false;
   4369    }
   4370 
   4371    needsWrapping = true;
   4372  }
   4373 
   4374  elements.initialize(data, &valuesObj->as<ArrayObject>(), needsWrapping);
   4375  return true;
   4376 }
   4377 
   4378 static JSFunction* NewPromiseCombinatorElementFunction(
   4379    JSContext* cx, Native native,
   4380    Handle<PromiseCombinatorDataHolder*> dataHolder, uint32_t index,
   4381    Handle<Value> maybeResolveFunc) {
   4382  JSFunction* fn = NewNativeFunction(
   4383      cx, native, 1, nullptr, gc::AllocKind::FUNCTION_EXTENDED, GenericObject);
   4384  if (!fn) {
   4385    return nullptr;
   4386  }
   4387 
   4388  // See the PromiseCombinatorElementFunctionSlots comment for an explanation of
   4389  // how these two slots are used.
   4390  if (maybeResolveFunc.isObject()) {
   4391    fn->setExtendedSlot(
   4392        PromiseCombinatorElementFunctionSlot_ElementIndexOrResolveFunc,
   4393        maybeResolveFunc);
   4394    fn->setExtendedSlot(PromiseCombinatorElementFunctionSlot_Data, NullValue());
   4395  } else {
   4396    fn->setExtendedSlot(
   4397        PromiseCombinatorElementFunctionSlot_ElementIndexOrResolveFunc,
   4398        Int32Value(index));
   4399    fn->setExtendedSlot(PromiseCombinatorElementFunctionSlot_Data,
   4400                        ObjectValue(*dataHolder));
   4401  }
   4402  return fn;
   4403 }
   4404 
   4405 /**
   4406 * ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
   4407 *
   4408 * Unified implementation of
   4409 *
   4410 * Promise.all Resolve Element Functions
   4411 * https://tc39.es/ecma262/#sec-promise.all-resolve-element-functions
   4412 *
   4413 * Steps 1-4.
   4414 *
   4415 * Promise.allSettled Resolve Element Functions
   4416 * https://tc39.es/ecma262/#sec-promise.allsettled-resolve-element-functions
   4417 *
   4418 * Steps 1-5.
   4419 *
   4420 * Promise.allSettled Reject Element Functions
   4421 * https://tc39.es/ecma262/#sec-promise.allsettled-reject-element-functions
   4422 *
   4423 * Steps 1-5.
   4424 *
   4425 * Promise.any Reject Element Functions
   4426 * https://tc39.es/ecma262/#sec-promise.any-reject-element-functions
   4427 *
   4428 * Steps 1-4.
   4429 *
   4430 * Common implementation for Promise combinator element functions to check if
   4431 * they've already been called.
   4432 */
   4433 static bool PromiseCombinatorElementFunctionAlreadyCalled(
   4434    const CallArgs& args, MutableHandle<PromiseCombinatorDataHolder*> data,
   4435    uint32_t* index) {
   4436  // Step 1. Let F be the active function object.
   4437  JSFunction* fn = &args.callee().as<JSFunction>();
   4438 
   4439  // Promise.{all,any} functions
   4440  // Step 2. If F.[[AlreadyCalled]] is true, return undefined.
   4441  // Promise.allSettled functions
   4442  // Step 2. Let alreadyCalled be F.[[AlreadyCalled]].
   4443  // Step 3. If alreadyCalled.[[Value]] is true, return undefined.
   4444  //
   4445  // We use the existence of the data holder as a signal for whether the Promise
   4446  // combinator element function was already called. Upon resolution, it's reset
   4447  // to `undefined`.
   4448  //
   4449  // For Promise.allSettled, the [[AlreadyCalled]] state must be shared by the
   4450  // two functions, so we always use the resolve function's state.
   4451 
   4452  constexpr size_t indexOrResolveFuncSlot =
   4453      PromiseCombinatorElementFunctionSlot_ElementIndexOrResolveFunc;
   4454  if (fn->getExtendedSlot(indexOrResolveFuncSlot).isObject()) {
   4455    // This is a reject function for Promise.allSettled. Get the corresponding
   4456    // resolve function.
   4457    Value slotVal = fn->getExtendedSlot(indexOrResolveFuncSlot);
   4458    fn = &slotVal.toObject().as<JSFunction>();
   4459  }
   4460  MOZ_RELEASE_ASSERT(fn->getExtendedSlot(indexOrResolveFuncSlot).isInt32());
   4461 
   4462  const Value& dataVal =
   4463      fn->getExtendedSlot(PromiseCombinatorElementFunctionSlot_Data);
   4464  if (dataVal.isUndefined()) {
   4465    return true;
   4466  }
   4467 
   4468  data.set(&dataVal.toObject().as<PromiseCombinatorDataHolder>());
   4469 
   4470  // Promise.{all,any} functions
   4471  // Step 3. Set F.[[AlreadyCalled]] to true.
   4472  // Promise.allSettled functions
   4473  // Step 4. Set alreadyCalled.[[Value]] to true.
   4474  fn->setExtendedSlot(PromiseCombinatorElementFunctionSlot_Data,
   4475                      UndefinedValue());
   4476 
   4477  // Promise.{all,any} functions
   4478  // Step 4. Let index be F.[[Index]].
   4479  // Promise.allSettled functions
   4480  // Step 5. Let index be F.[[Index]].
   4481  int32_t idx = fn->getExtendedSlot(indexOrResolveFuncSlot).toInt32();
   4482  MOZ_ASSERT(idx >= 0);
   4483  *index = uint32_t(idx);
   4484 
   4485  return false;
   4486 }
   4487 
   4488 /**
   4489 * ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
   4490 *
   4491 * PerformPromiseAll ( iteratorRecord, constructor, resultCapability,
   4492 *                     promiseResolve )
   4493 * https://tc39.es/ecma262/#sec-performpromiseall
   4494 */
   4495 [[nodiscard]] static bool PerformPromiseAll(
   4496    JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
   4497    Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
   4498    bool* done) {
   4499  *done = false;
   4500 
   4501  MOZ_ASSERT(C->isConstructor());
   4502 
   4503  // Step 1. Let values be a new empty List.
   4504  Rooted<PromiseCombinatorElements> values(cx);
   4505  if (!NewPromiseCombinatorElements(cx, resultCapability, &values)) {
   4506    return false;
   4507  }
   4508 
   4509  // Step 2. Let remainingElementsCount be the Record { [[Value]]: 1 }.
   4510  //
   4511  // Create our data holder that holds all the things shared across
   4512  // every step of the iterator.  In particular, this holds the
   4513  // remainingElementsCount (as an integer reserved slot), the array of
   4514  // values, and the resolve function from our PromiseCapability.
   4515  Rooted<PromiseCombinatorDataHolder*> dataHolder(cx);
   4516  dataHolder = PromiseCombinatorDataHolder::New(
   4517      cx, resultCapability.promise(), values, resultCapability.resolve());
   4518  if (!dataHolder) {
   4519    return false;
   4520  }
   4521 
   4522  // Step 3. Let index be 0.
   4523  uint32_t index = 0;
   4524 
   4525  auto getResolveAndReject = [cx, &resultCapability, &values, &dataHolder,
   4526                              &index](MutableHandleValue resolveFunVal,
   4527                                      MutableHandleValue rejectFunVal) {
   4528    // Step 4.c. Append undefined to values.
   4529    if (!values.pushUndefined(cx)) {
   4530      return false;
   4531    }
   4532 
   4533    // Steps 4.e-l.
   4534    JSFunction* resolveFunc = NewPromiseCombinatorElementFunction(
   4535        cx, PromiseAllResolveElementFunction, dataHolder, index,
   4536        UndefinedHandleValue);
   4537    if (!resolveFunc) {
   4538      return false;
   4539    }
   4540 
   4541    // Step 4.m. Set remainingElementsCount.[[Value]] to
   4542    //           remainingElementsCount.[[Value]] + 1.
   4543    dataHolder->increaseRemainingCount();
   4544 
   4545    // Step 4.o. Set index to index + 1.
   4546    index++;
   4547    MOZ_ASSERT(index > 0);
   4548 
   4549    resolveFunVal.setObject(*resolveFunc);
   4550    rejectFunVal.setObject(*resultCapability.reject());
   4551    return true;
   4552  };
   4553 
   4554  // Step 4. Repeat,
   4555  if (!CommonPerformPromiseCombinator(
   4556          cx, iterator, C, resultCapability.promise(), promiseResolve, done,
   4557          true, getResolveAndReject)) {
   4558    return false;
   4559  }
   4560 
   4561  // Step 4.b.i. Set remainingElementsCount.[[Value]] to
   4562  //             remainingElementsCount.[[Value]] - 1.
   4563  int32_t remainingCount = dataHolder->decreaseRemainingCount();
   4564 
   4565  // Step 4.b.ii. If remainingElementsCount.[[Value]] is 0, then
   4566  if (remainingCount == 0) {
   4567    // Step 4.b.ii.1. Let valuesArray be CreateArrayFromList(values).
   4568    // (already performed)
   4569 
   4570    // Step 4.b.ii.2. Perform
   4571    //                ? Call(resultCapability.[[Resolve]], undefined,
   4572    //                       « valuesArray »).
   4573    return CallPromiseResolveFunction(cx, resultCapability.resolve(),
   4574                                      values.value(),
   4575                                      resultCapability.promise());
   4576  }
   4577 
   4578  // Step 4.d.iii. Return resultCapability.[[Promise]].
   4579  return true;
   4580 }
   4581 
   4582 /**
   4583 * ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
   4584 *
   4585 * Promise.all Resolve Element Functions
   4586 * https://tc39.es/ecma262/#sec-promise.all-resolve-element-functions
   4587 */
   4588 static bool PromiseAllResolveElementFunction(JSContext* cx, unsigned argc,
   4589                                             Value* vp) {
   4590  CallArgs args = CallArgsFromVp(argc, vp);
   4591  HandleValue xVal = args.get(0);
   4592 
   4593  // Steps 1-4.
   4594  Rooted<PromiseCombinatorDataHolder*> data(cx);
   4595  uint32_t index;
   4596  if (PromiseCombinatorElementFunctionAlreadyCalled(args, &data, &index)) {
   4597    args.rval().setUndefined();
   4598    return true;
   4599  }
   4600 
   4601  // Step 5. Let values be F.[[Values]].
   4602  Rooted<PromiseCombinatorElements> values(cx);
   4603  if (!GetPromiseCombinatorElements(cx, data, &values)) {
   4604    return false;
   4605  }
   4606 
   4607  // Step 8. Set values[index] to x.
   4608  if (!values.setElement(cx, index, xVal)) {
   4609    return false;
   4610  }
   4611 
   4612  // (reordered)
   4613  // Step 7. Let remainingElementsCount be F.[[RemainingElements]].
   4614  //
   4615  // Step 9. Set remainingElementsCount.[[Value]] to
   4616  //         remainingElementsCount.[[Value]] - 1.
   4617  uint32_t remainingCount = data->decreaseRemainingCount();
   4618 
   4619  // Step 10. If remainingElementsCount.[[Value]] is 0, then
   4620  if (remainingCount == 0) {
   4621    // Step 10.a. Let valuesArray be CreateArrayFromList(values).
   4622    // (already performed)
   4623 
   4624    // (reordered)
   4625    // Step 6. Let promiseCapability be F.[[Capability]].
   4626    //
   4627    // Step 10.b. Return
   4628    //            ? Call(promiseCapability.[[Resolve]], undefined,
   4629    //                   « valuesArray »).
   4630    RootedObject resolveAllFun(cx, data->resolveOrRejectObj());
   4631    RootedObject promiseObj(cx, data->promiseObj());
   4632    if (!CallPromiseResolveFunction(cx, resolveAllFun, values.value(),
   4633                                    promiseObj)) {
   4634      return false;
   4635    }
   4636  }
   4637 
   4638  // Step 11. Return undefined.
   4639  args.rval().setUndefined();
   4640  return true;
   4641 }
   4642 
   4643 /**
   4644 * ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
   4645 *
   4646 * Promise.race ( iterable )
   4647 * https://tc39.es/ecma262/#sec-promise.race
   4648 */
   4649 static bool Promise_static_race(JSContext* cx, unsigned argc, Value* vp) {
   4650  CallArgs args = CallArgsFromVp(argc, vp);
   4651  return CommonPromiseCombinator(cx, args, CombinatorKind::Race);
   4652 }
   4653 
   4654 /**
   4655 * ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
   4656 *
   4657 * PerformPromiseRace ( iteratorRecord, constructor, resultCapability,
   4658 *                      promiseResolve )
   4659 * https://tc39.es/ecma262/#sec-performpromiserace
   4660 */
   4661 [[nodiscard]] static bool PerformPromiseRace(
   4662    JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
   4663    Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
   4664    bool* done) {
   4665  *done = false;
   4666 
   4667  MOZ_ASSERT(C->isConstructor());
   4668 
   4669  // BlockOnPromise fast path requires the passed onFulfilled function
   4670  // doesn't return an object value, because otherwise the skipped promise
   4671  // creation is detectable due to missing property lookups.
   4672  bool isDefaultResolveFn =
   4673      IsNativeFunction(resultCapability.resolve(), ResolvePromiseFunction);
   4674 
   4675  auto getResolveAndReject = [&resultCapability](
   4676                                 MutableHandleValue resolveFunVal,
   4677                                 MutableHandleValue rejectFunVal) {
   4678    resolveFunVal.setObject(*resultCapability.resolve());
   4679    rejectFunVal.setObject(*resultCapability.reject());
   4680    return true;
   4681  };
   4682 
   4683  // Step 1. Repeat,
   4684  return CommonPerformPromiseCombinator(
   4685      cx, iterator, C, resultCapability.promise(), promiseResolve, done,
   4686      isDefaultResolveFn, getResolveAndReject);
   4687 }
   4688 
   4689 enum class PromiseAllSettledElementFunctionKind { Resolve, Reject };
   4690 
   4691 template <PromiseAllSettledElementFunctionKind Kind>
   4692 static bool PromiseAllSettledElementFunction(JSContext* cx, unsigned argc,
   4693                                             Value* vp);
   4694 
   4695 /**
   4696 * ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
   4697 *
   4698 * Promise.allSettled ( iterable )
   4699 * https://tc39.es/ecma262/#sec-promise.allsettled
   4700 */
   4701 static bool Promise_static_allSettled(JSContext* cx, unsigned argc, Value* vp) {
   4702  CallArgs args = CallArgsFromVp(argc, vp);
   4703  return CommonPromiseCombinator(cx, args, CombinatorKind::AllSettled);
   4704 }
   4705 
   4706 /**
   4707 * ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
   4708 *
   4709 * PerformPromiseAllSettled ( iteratorRecord, constructor, resultCapability,
   4710 *                            promiseResolve )
   4711 * https://tc39.es/ecma262/#sec-performpromiseallsettled
   4712 */
   4713 [[nodiscard]] static bool PerformPromiseAllSettled(
   4714    JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
   4715    Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
   4716    bool* done) {
   4717  *done = false;
   4718 
   4719  MOZ_ASSERT(C->isConstructor());
   4720 
   4721  // Step 1. Let values be a new empty List.
   4722  Rooted<PromiseCombinatorElements> values(cx);
   4723  if (!NewPromiseCombinatorElements(cx, resultCapability, &values)) {
   4724    return false;
   4725  }
   4726 
   4727  // Step 2. Let remainingElementsCount be the Record { [[Value]]: 1 }.
   4728  //
   4729  // Create our data holder that holds all the things shared across every step
   4730  // of the iterator. In particular, this holds the remainingElementsCount
   4731  // (as an integer reserved slot), the array of values, and the resolve
   4732  // function from our PromiseCapability.
   4733  Rooted<PromiseCombinatorDataHolder*> dataHolder(cx);
   4734  dataHolder = PromiseCombinatorDataHolder::New(
   4735      cx, resultCapability.promise(), values, resultCapability.resolve());
   4736  if (!dataHolder) {
   4737    return false;
   4738  }
   4739 
   4740  // Step 3. Let index be 0.
   4741  uint32_t index = 0;
   4742 
   4743  auto getResolveAndReject = [cx, &values, &dataHolder, &index](
   4744                                 MutableHandleValue resolveFunVal,
   4745                                 MutableHandleValue rejectFunVal) {
   4746    // Step 4.c. Append undefined to values.
   4747    if (!values.pushUndefined(cx)) {
   4748      return false;
   4749    }
   4750 
   4751    auto PromiseAllSettledResolveElementFunction =
   4752        PromiseAllSettledElementFunction<
   4753            PromiseAllSettledElementFunctionKind::Resolve>;
   4754    auto PromiseAllSettledRejectElementFunction =
   4755        PromiseAllSettledElementFunction<
   4756            PromiseAllSettledElementFunctionKind::Reject>;
   4757 
   4758    // Steps 4.e-m.
   4759    JSFunction* resolveFunc = NewPromiseCombinatorElementFunction(
   4760        cx, PromiseAllSettledResolveElementFunction, dataHolder, index,
   4761        UndefinedHandleValue);
   4762    if (!resolveFunc) {
   4763      return false;
   4764    }
   4765    resolveFunVal.setObject(*resolveFunc);
   4766 
   4767    // Steps 4.n-u.
   4768    JSFunction* rejectFunc = NewPromiseCombinatorElementFunction(
   4769        cx, PromiseAllSettledRejectElementFunction, dataHolder, index,
   4770        resolveFunVal);
   4771    if (!rejectFunc) {
   4772      return false;
   4773    }
   4774    rejectFunVal.setObject(*rejectFunc);
   4775 
   4776    // Step 4.v. Set remainingElementsCount.[[Value]] to
   4777    //           remainingElementsCount.[[Value]] + 1.
   4778    dataHolder->increaseRemainingCount();
   4779 
   4780    // Step 4.x. Set index to index + 1.
   4781    index++;
   4782    MOZ_ASSERT(index > 0);
   4783 
   4784    return true;
   4785  };
   4786 
   4787  // Step 4. Repeat,
   4788  if (!CommonPerformPromiseCombinator(
   4789          cx, iterator, C, resultCapability.promise(), promiseResolve, done,
   4790          true, getResolveAndReject)) {
   4791    return false;
   4792  }
   4793 
   4794  // Step 4.b.ii. Set remainingElementsCount.[[Value]] to
   4795  //              remainingElementsCount.[[Value]] - 1.
   4796  int32_t remainingCount = dataHolder->decreaseRemainingCount();
   4797 
   4798  // Step 4.b.ii. If remainingElementsCount.[[Value]] is 0, then
   4799  if (remainingCount == 0) {
   4800    // Step 4.b.ii.1. Let valuesArray be CreateArrayFromList(values).
   4801    // (already performed)
   4802 
   4803    // Step 4.b.ii.2. Perform
   4804    //                ? Call(resultCapability.[[Resolve]], undefined,
   4805    //                       « valuesArray »).
   4806    return CallPromiseResolveFunction(cx, resultCapability.resolve(),
   4807                                      values.value(),
   4808                                      resultCapability.promise());
   4809  }
   4810 
   4811  return true;
   4812 }
   4813 
   4814 /**
   4815 * ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
   4816 *
   4817 * Unified implementation of
   4818 *
   4819 * Promise.allSettled Resolve Element Functions
   4820 * https://tc39.es/ecma262/#sec-promise.allsettled-resolve-element-functions
   4821 * Promise.allSettled Reject Element Functions
   4822 * https://tc39.es/ecma262/#sec-promise.allsettled-reject-element-functions
   4823 */
   4824 template <PromiseAllSettledElementFunctionKind Kind>
   4825 static bool PromiseAllSettledElementFunction(JSContext* cx, unsigned argc,
   4826                                             Value* vp) {
   4827  CallArgs args = CallArgsFromVp(argc, vp);
   4828  HandleValue valueOrReason = args.get(0);
   4829 
   4830  // Steps 1-5.
   4831  Rooted<PromiseCombinatorDataHolder*> data(cx);
   4832  uint32_t index;
   4833  if (PromiseCombinatorElementFunctionAlreadyCalled(args, &data, &index)) {
   4834    args.rval().setUndefined();
   4835    return true;
   4836  }
   4837 
   4838  // Step 6. Let values be F.[[Values]].
   4839  Rooted<PromiseCombinatorElements> values(cx);
   4840  if (!GetPromiseCombinatorElements(cx, data, &values)) {
   4841    return false;
   4842  }
   4843 
   4844  // Step 9. Let obj be OrdinaryObjectCreate(%Object.prototype%).
   4845  Rooted<PlainObject*> obj(cx, NewPlainObject(cx));
   4846  if (!obj) {
   4847    return false;
   4848  }
   4849 
   4850  // Promise.allSettled Resolve Element Functions
   4851  // Step 10. Perform ! CreateDataPropertyOrThrow(obj, "status", "fulfilled").
   4852  // Promise.allSettled Reject Element Functions
   4853  // Step 10. Perform ! CreateDataPropertyOrThrow(obj, "status", "rejected").
   4854  RootedId id(cx, NameToId(cx->names().status));
   4855  RootedValue statusValue(cx);
   4856  if (Kind == PromiseAllSettledElementFunctionKind::Resolve) {
   4857    statusValue.setString(cx->names().fulfilled);
   4858  } else {
   4859    statusValue.setString(cx->names().rejected);
   4860  }
   4861  if (!NativeDefineDataProperty(cx, obj, id, statusValue, JSPROP_ENUMERATE)) {
   4862    return false;
   4863  }
   4864 
   4865  // Promise.allSettled Resolve Element Functions
   4866  // Step 11. Perform ! CreateDataPropertyOrThrow(obj, "value", x).
   4867  // Promise.allSettled Reject Element Functions
   4868  // Step 11. Perform ! CreateDataPropertyOrThrow(obj, "reason", x).
   4869  if (Kind == PromiseAllSettledElementFunctionKind::Resolve) {
   4870    id = NameToId(cx->names().value);
   4871  } else {
   4872    id = NameToId(cx->names().reason);
   4873  }
   4874  if (!NativeDefineDataProperty(cx, obj, id, valueOrReason, JSPROP_ENUMERATE)) {
   4875    return false;
   4876  }
   4877 
   4878  // Step 12. Set values[index] to obj.
   4879  RootedValue objVal(cx, ObjectValue(*obj));
   4880  if (!values.setElement(cx, index, objVal)) {
   4881    return false;
   4882  }
   4883 
   4884  // (reordered)
   4885  // Step 8. Let remainingElementsCount be F.[[RemainingElements]].
   4886  //
   4887  // Step 13. Set remainingElementsCount.[[Value]] to
   4888  // remainingElementsCount.[[Value]] - 1.
   4889  uint32_t remainingCount = data->decreaseRemainingCount();
   4890 
   4891  // Step 14. If remainingElementsCount.[[Value]] is 0, then
   4892  if (remainingCount == 0) {
   4893    // Step 14.a. Let valuesArray be ! CreateArrayFromList(values).
   4894    // (already performed)
   4895 
   4896    // (reordered)
   4897    // Step 7. Let promiseCapability be F.[[Capability]].
   4898    //
   4899    // Step 14.b. Return
   4900    //            ? Call(promiseCapability.[[Resolve]], undefined,
   4901    //                   « valuesArray »).
   4902    RootedObject resolveAllFun(cx, data->resolveOrRejectObj());
   4903    RootedObject promiseObj(cx, data->promiseObj());
   4904    if (!CallPromiseResolveFunction(cx, resolveAllFun, values.value(),
   4905                                    promiseObj)) {
   4906      return false;
   4907    }
   4908  }
   4909 
   4910  // Step 15. Return undefined.
   4911  args.rval().setUndefined();
   4912  return true;
   4913 }
   4914 
   4915 /**
   4916 * ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
   4917 *
   4918 * Promise.any ( iterable )
   4919 * https://tc39.es/ecma262/#sec-promise.any
   4920 */
   4921 static bool Promise_static_any(JSContext* cx, unsigned argc, Value* vp) {
   4922  CallArgs args = CallArgsFromVp(argc, vp);
   4923  return CommonPromiseCombinator(cx, args, CombinatorKind::Any);
   4924 }
   4925 
   4926 static bool PromiseAnyRejectElementFunction(JSContext* cx, unsigned argc,
   4927                                            Value* vp);
   4928 
   4929 static void ThrowAggregateError(JSContext* cx,
   4930                                Handle<PromiseCombinatorElements> errors,
   4931                                HandleObject promise);
   4932 
   4933 /**
   4934 * ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
   4935 *
   4936 * Promise.any ( iterable )
   4937 * https://tc39.es/ecma262/#sec-promise.any
   4938 * PerformPromiseAny ( iteratorRecord, constructor, resultCapability,
   4939 *                     promiseResolve )
   4940 * https://tc39.es/ecma262/#sec-performpromiseany
   4941 */
   4942 [[nodiscard]] static bool PerformPromiseAny(
   4943    JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
   4944    Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
   4945    bool* done) {
   4946  MOZ_ASSERT(C->isConstructor());
   4947 
   4948  *done = false;
   4949 
   4950  // Step 1. Let errors be a new empty List.
   4951  Rooted<PromiseCombinatorElements> errors(cx);
   4952  if (!NewPromiseCombinatorElements(cx, resultCapability, &errors)) {
   4953    return false;
   4954  }
   4955 
   4956  // Step 2. Let remainingElementsCount be the Record { [[Value]]: 1 }.
   4957  //
   4958  // Create our data holder that holds all the things shared across every step
   4959  // of the iterator. In particular, this holds the remainingElementsCount (as
   4960  // an integer reserved slot), the array of errors, and the reject function
   4961  // from our PromiseCapability.
   4962  Rooted<PromiseCombinatorDataHolder*> dataHolder(cx);
   4963  dataHolder = PromiseCombinatorDataHolder::New(
   4964      cx, resultCapability.promise(), errors, resultCapability.reject());
   4965  if (!dataHolder) {
   4966    return false;
   4967  }
   4968 
   4969  // Step 3. Let index be 0.
   4970  uint32_t index = 0;
   4971 
   4972  auto getResolveAndReject = [cx, &resultCapability, &errors, &dataHolder,
   4973                              &index](MutableHandleValue resolveFunVal,
   4974                                      MutableHandleValue rejectFunVal) {
   4975    // Step 4.c. Append undefined to errors.
   4976    if (!errors.pushUndefined(cx)) {
   4977      return false;
   4978    }
   4979 
   4980    // Steps 4.e-l.
   4981    JSFunction* rejectFunc = NewPromiseCombinatorElementFunction(
   4982        cx, PromiseAnyRejectElementFunction, dataHolder, index,
   4983        UndefinedHandleValue);
   4984    if (!rejectFunc) {
   4985      return false;
   4986    }
   4987 
   4988    // Step 4.m. Set remainingElementsCount.[[Value]] to
   4989    //           remainingElementsCount.[[Value]] + 1.
   4990    dataHolder->increaseRemainingCount();
   4991 
   4992    // Step 4.o. Set index to index + 1.
   4993    index++;
   4994    MOZ_ASSERT(index > 0);
   4995 
   4996    resolveFunVal.setObject(*resultCapability.resolve());
   4997    rejectFunVal.setObject(*rejectFunc);
   4998    return true;
   4999  };
   5000 
   5001  // BlockOnPromise fast path requires the passed onFulfilled function doesn't
   5002  // return an object value, because otherwise the skipped promise creation is
   5003  // detectable due to missing property lookups.
   5004  bool isDefaultResolveFn =
   5005      IsNativeFunction(resultCapability.resolve(), ResolvePromiseFunction);
   5006 
   5007  // Step 4. Repeat,
   5008  if (!CommonPerformPromiseCombinator(
   5009          cx, iterator, C, resultCapability.promise(), promiseResolve, done,
   5010          isDefaultResolveFn, getResolveAndReject)) {
   5011    return false;
   5012  }
   5013 
   5014  // Step 4.b.i. Set remainingElementsCount.[[Value]] to
   5015  //             remainingElementsCount.[[Value]] - 1..
   5016  int32_t remainingCount = dataHolder->decreaseRemainingCount();
   5017 
   5018  // Step 4.b.ii. If remainingElementsCount.[[Value]] = 0, then
   5019  if (remainingCount == 0) {
   5020    ThrowAggregateError(cx, errors, resultCapability.promise());
   5021    return false;
   5022  }
   5023 
   5024  // Step 4.b.iii. Return resultCapability.[[Promise]].
   5025  return true;
   5026 }
   5027 
   5028 /**
   5029 * ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
   5030 *
   5031 * Promise.any Reject Element Functions
   5032 * https://tc39.es/ecma262/#sec-promise.any-reject-element-functions
   5033 */
   5034 static bool PromiseAnyRejectElementFunction(JSContext* cx, unsigned argc,
   5035                                            Value* vp) {
   5036  CallArgs args = CallArgsFromVp(argc, vp);
   5037  HandleValue xVal = args.get(0);
   5038 
   5039  // Steps 1-4.
   5040  Rooted<PromiseCombinatorDataHolder*> data(cx);
   5041  uint32_t index;
   5042  if (PromiseCombinatorElementFunctionAlreadyCalled(args, &data, &index)) {
   5043    args.rval().setUndefined();
   5044    return true;
   5045  }
   5046 
   5047  // Step 5.
   5048  Rooted<PromiseCombinatorElements> errors(cx);
   5049  if (!GetPromiseCombinatorElements(cx, data, &errors)) {
   5050    return false;
   5051  }
   5052 
   5053  // Step 8.
   5054  if (!errors.setElement(cx, index, xVal)) {
   5055    return false;
   5056  }
   5057 
   5058  // Steps 7 and 9.
   5059  uint32_t remainingCount = data->decreaseRemainingCount();
   5060 
   5061  // Step 10.
   5062  if (remainingCount == 0) {
   5063    // Step 6 (Adapted to work with PromiseCombinatorDataHolder's layout).
   5064    RootedObject rejectFun(cx, data->resolveOrRejectObj());
   5065    RootedObject promiseObj(cx, data->promiseObj());
   5066 
   5067    // Steps 10.a-b.
   5068    ThrowAggregateError(cx, errors, promiseObj);
   5069 
   5070    RootedValue reason(cx);
   5071    Rooted<SavedFrame*> stack(cx);
   5072    if (!MaybeGetAndClearExceptionAndStack(cx, &reason, &stack)) {
   5073      return false;
   5074    }
   5075 
   5076    // Step 10.c.
   5077    if (!CallPromiseRejectFunction(cx, rejectFun, reason, promiseObj, stack,
   5078                                   UnhandledRejectionBehavior::Report)) {
   5079      return false;
   5080    }
   5081  }
   5082 
   5083  // Step 11.
   5084  args.rval().setUndefined();
   5085  return true;
   5086 }
   5087 
   5088 /**
   5089 * ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
   5090 *
   5091 * PerformPromiseAny ( iteratorRecord, constructor, resultCapability,
   5092 *                     promiseResolve )
   5093 * https://tc39.es/ecma262/#sec-performpromiseany
   5094 *
   5095 * Steps 4.b.ii.1-3
   5096 */
   5097 static void ThrowAggregateError(JSContext* cx,
   5098                                Handle<PromiseCombinatorElements> errors,
   5099                                HandleObject promise) {
   5100  MOZ_ASSERT(!cx->isExceptionPending());
   5101 
   5102  // Create the AggregateError in the same realm as the array object.
   5103  AutoRealm ar(cx, errors.unwrappedArray());
   5104 
   5105  RootedObject allocationSite(cx);
   5106  mozilla::Maybe<JS::AutoSetAsyncStackForNewCalls> asyncStack;
   5107 
   5108  // Provide a more useful error stack if possible: This function is typically
   5109  // called from Promise job queue, which doesn't have any JS frames on the
   5110  // stack. So when we create the AggregateError below, its stack property will
   5111  // be set to the empty string, which makes it harder to debug the error cause.
   5112  // To avoid this situation set-up an async stack based on the Promise
   5113  // allocation site, which should point to calling site of |Promise.any|.
   5114  if (promise->is<PromiseObject>()) {
   5115    allocationSite = promise->as<PromiseObject>().allocationSite();
   5116    if (allocationSite) {
   5117      asyncStack.emplace(
   5118          cx, allocationSite, "Promise.any",
   5119          JS::AutoSetAsyncStackForNewCalls::AsyncCallKind::IMPLICIT);
   5120    }
   5121  }
   5122 
   5123  // Step 4.b.ii.1. Let error be a newly created AggregateError object.
   5124  //
   5125  // AutoSetAsyncStackForNewCalls requires a new activation before it takes
   5126  // effect, so call into the self-hosting helper to set-up new call frames.
   5127  RootedValue error(cx);
   5128  if (!GetAggregateError(cx, JSMSG_PROMISE_ANY_REJECTION, &error)) {
   5129    return;
   5130  }
   5131 
   5132  // Step 4.b.ii.2. Perform ! DefinePropertyOrThrow(
   5133  //                  error, "errors", PropertyDescriptor {
   5134  //                    [[Configurable]]: true, [[Enumerable]]: false,
   5135  //                    [[Writable]]: true,
   5136  //                    [[Value]]: ! CreateArrayFromList(errors) }).
   5137  //
   5138  // |error| isn't guaranteed to be an AggregateError in case of OOM or stack
   5139  // overflow.
   5140  Rooted<SavedFrame*> stack(cx);
   5141  if (error.isObject() && error.toObject().is<ErrorObject>()) {
   5142    Rooted<ErrorObject*> errorObj(cx, &error.toObject().as<ErrorObject>());
   5143    if (errorObj->type() == JSEXN_AGGREGATEERR) {
   5144      RootedValue errorsVal(cx, JS::ObjectValue(*errors.unwrappedArray()));
   5145      if (!NativeDefineDataProperty(cx, errorObj, cx->names().errors, errorsVal,
   5146                                    0)) {
   5147        return;
   5148      }
   5149 
   5150      // Adopt the existing saved frames when present.
   5151      if (JSObject* errorStack = errorObj->stack()) {
   5152        stack = &errorStack->as<SavedFrame>();
   5153      }
   5154    }
   5155  }
   5156 
   5157  // Step 4.b.ii.3. Return ThrowCompletion(error).
   5158  cx->setPendingException(error, stack);
   5159 }
   5160 
   5161 /**
   5162 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   5163 *
   5164 * Unified implementation of
   5165 *
   5166 * Promise.reject ( r )
   5167 * https://tc39.es/ecma262/#sec-promise.reject
   5168 * NewPromiseCapability ( C )
   5169 * https://tc39.es/ecma262/#sec-newpromisecapability
   5170 * Promise.resolve ( x )
   5171 * https://tc39.es/ecma262/#sec-promise.resolve
   5172 * PromiseResolve ( C, x )
   5173 * https://tc39.es/ecma262/#sec-promise-resolve
   5174 */
   5175 [[nodiscard]] static JSObject* CommonStaticResolveRejectImpl(
   5176    JSContext* cx, HandleValue thisVal, HandleValue argVal,
   5177    ResolutionMode mode) {
   5178  // Promise.reject
   5179  // Step 1. Let C be the this value.
   5180  // Step 2. Let promiseCapability be ? NewPromiseCapability(C).
   5181  //
   5182  // Promise.reject => NewPromiseCapability
   5183  // Step 1. If IsConstructor(C) is false, throw a TypeError exception.
   5184  //
   5185  // Promise.resolve
   5186  // Step 1. Let C be the this value.
   5187  // Step 2. If Type(C) is not Object, throw a TypeError exception.
   5188  if (!thisVal.isObject()) {
   5189    const char* msg = mode == ResolveMode ? "Receiver of Promise.resolve call"
   5190                                          : "Receiver of Promise.reject call";
   5191    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   5192                              JSMSG_OBJECT_REQUIRED, msg);
   5193    return nullptr;
   5194  }
   5195  RootedObject C(cx, &thisVal.toObject());
   5196 
   5197  // Promise.resolve
   5198  // Step 3. Return ? PromiseResolve(C, x).
   5199  //
   5200  // PromiseResolve
   5201  // Step 1. Assert: Type(C) is Object.
   5202  // (implicit)
   5203  if (mode == ResolveMode && argVal.isObject()) {
   5204    RootedObject xObj(cx, &argVal.toObject());
   5205    bool isPromise = false;
   5206    if (xObj->is<PromiseObject>()) {
   5207      isPromise = true;
   5208    } else if (IsWrapper(xObj)) {
   5209      // Treat instances of Promise from other compartments as Promises
   5210      // here, too.
   5211      // It's important to do the GetProperty for the `constructor`
   5212      // below through the wrapper, because wrappers can change the
   5213      // outcome, so instead of unwrapping and then performing the
   5214      // GetProperty, just check here and then operate on the original
   5215      // object again.
   5216      if (xObj->canUnwrapAs<PromiseObject>()) {
   5217        isPromise = true;
   5218      }
   5219    }
   5220 
   5221    // PromiseResolve
   5222    // Step 2. If IsPromise(x) is true, then
   5223    if (isPromise) {
   5224      // Step 2.a. Let xConstructor be ? Get(x, "constructor").
   5225      RootedValue ctorVal(cx);
   5226      if (!GetProperty(cx, xObj, xObj, cx->names().constructor, &ctorVal)) {
   5227        return nullptr;
   5228      }
   5229 
   5230      // Step 2.b. If SameValue(xConstructor, C) is true, return x.
   5231      if (ctorVal == thisVal) {
   5232        return xObj;
   5233      }
   5234    }
   5235  }
   5236 
   5237  // Promise.reject
   5238  // Step 2. Let promiseCapability be ? NewPromiseCapability(C).
   5239  // PromiseResolve
   5240  // Step 3. Let promiseCapability be ? NewPromiseCapability(C).
   5241  Rooted<PromiseCapability> capability(cx);
   5242  if (!NewPromiseCapability(cx, C, &capability, true)) {
   5243    return nullptr;
   5244  }
   5245 
   5246  HandleObject promise = capability.promise();
   5247  if (mode == ResolveMode) {
   5248    // PromiseResolve
   5249    // Step 4. Perform ? Call(promiseCapability.[[Resolve]], undefined, « x »).
   5250    if (!CallPromiseResolveFunction(cx, capability.resolve(), argVal,
   5251                                    promise)) {
   5252      return nullptr;
   5253    }
   5254  } else {
   5255    // Promise.reject
   5256    // Step 3. Perform ? Call(promiseCapability.[[Reject]], undefined, « r »).
   5257    if (!CallPromiseRejectFunction(cx, capability.reject(), argVal, promise,
   5258                                   nullptr,
   5259                                   UnhandledRejectionBehavior::Report)) {
   5260      return nullptr;
   5261    }
   5262  }
   5263 
   5264  // Promise.reject
   5265  // Step 4. Return promiseCapability.[[Promise]].
   5266  // PromiseResolve
   5267  // Step 5. Return promiseCapability.[[Promise]].
   5268  return promise;
   5269 }
   5270 
   5271 [[nodiscard]] JSObject* js::PromiseResolve(JSContext* cx,
   5272                                           HandleObject constructor,
   5273                                           HandleValue value) {
   5274  RootedValue C(cx, ObjectValue(*constructor));
   5275  return CommonStaticResolveRejectImpl(cx, C, value, ResolveMode);
   5276 }
   5277 
   5278 /**
   5279 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   5280 *
   5281 * Promise.reject ( r )
   5282 * https://tc39.es/ecma262/#sec-promise.reject
   5283 */
   5284 static bool Promise_reject(JSContext* cx, unsigned argc, Value* vp) {
   5285  CallArgs args = CallArgsFromVp(argc, vp);
   5286  HandleValue thisVal = args.thisv();
   5287  HandleValue argVal = args.get(0);
   5288  JSObject* result =
   5289      CommonStaticResolveRejectImpl(cx, thisVal, argVal, RejectMode);
   5290  if (!result) {
   5291    return false;
   5292  }
   5293  args.rval().setObject(*result);
   5294  return true;
   5295 }
   5296 
   5297 /**
   5298 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   5299 *
   5300 * Promise.reject ( r )
   5301 * https://tc39.es/ecma262/#sec-promise.reject
   5302 *
   5303 * Unforgeable version.
   5304 */
   5305 /* static */
   5306 PromiseObject* PromiseObject::unforgeableReject(JSContext* cx,
   5307                                                HandleValue value) {
   5308  cx->check(value);
   5309 
   5310  // Step 1. Let C be the this value.
   5311  // Step 2. Let promiseCapability be ? NewPromiseCapability(C).
   5312  Rooted<PromiseObject*> promise(
   5313      cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
   5314  if (!promise) {
   5315    return nullptr;
   5316  }
   5317 
   5318  MOZ_ASSERT(promise->state() == JS::PromiseState::Pending);
   5319  MOZ_ASSERT(IsPromiseWithDefaultResolvingFunction(promise));
   5320 
   5321  // Step 3. Perform ? Call(promiseCapability.[[Reject]], undefined, « r »).
   5322  if (!RejectPromiseInternal(cx, promise, value)) {
   5323    return nullptr;
   5324  }
   5325 
   5326  // Step 4. Return promiseCapability.[[Promise]].
   5327  return promise;
   5328 }
   5329 
   5330 /**
   5331 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   5332 *
   5333 * Promise.resolve ( x )
   5334 * https://tc39.es/ecma262/#sec-promise.resolve
   5335 */
   5336 bool js::Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp) {
   5337  CallArgs args = CallArgsFromVp(argc, vp);
   5338  HandleValue thisVal = args.thisv();
   5339  HandleValue argVal = args.get(0);
   5340  JSObject* result =
   5341      CommonStaticResolveRejectImpl(cx, thisVal, argVal, ResolveMode);
   5342  if (!result) {
   5343    return false;
   5344  }
   5345  args.rval().setObject(*result);
   5346  return true;
   5347 }
   5348 
   5349 /**
   5350 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   5351 *
   5352 * Promise.resolve ( x )
   5353 * https://tc39.es/ecma262/#sec-promise.resolve
   5354 *
   5355 * Unforgeable version.
   5356 */
   5357 /* static */
   5358 JSObject* PromiseObject::unforgeableResolve(JSContext* cx, HandleValue value) {
   5359  JSObject* promiseCtor = JS::GetPromiseConstructor(cx);
   5360  if (!promiseCtor) {
   5361    return nullptr;
   5362  }
   5363  RootedValue cVal(cx, ObjectValue(*promiseCtor));
   5364  return CommonStaticResolveRejectImpl(cx, cVal, value, ResolveMode);
   5365 }
   5366 
   5367 /**
   5368 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   5369 *
   5370 * Promise.resolve ( x )
   5371 * https://tc39.es/ecma262/#sec-promise.resolve
   5372 * PromiseResolve ( C, x )
   5373 * https://tc39.es/ecma262/#sec-promise-resolve
   5374 *
   5375 * Unforgeable version, where `x` is guaranteed not to be a promise.
   5376 */
   5377 /* static */
   5378 PromiseObject* PromiseObject::unforgeableResolveWithNonPromise(
   5379    JSContext* cx, HandleValue value) {
   5380  cx->check(value);
   5381 
   5382 #ifdef DEBUG
   5383  auto IsPromise = [](HandleValue value) {
   5384    if (!value.isObject()) {
   5385      return false;
   5386    }
   5387 
   5388    JSObject* obj = &value.toObject();
   5389    if (obj->is<PromiseObject>()) {
   5390      return true;
   5391    }
   5392 
   5393    if (!IsWrapper(obj)) {
   5394      return false;
   5395    }
   5396 
   5397    return obj->canUnwrapAs<PromiseObject>();
   5398  };
   5399  MOZ_ASSERT(!IsPromise(value), "must use unforgeableResolve with this value");
   5400 #endif
   5401 
   5402  // Promise.resolve
   5403  // Step 3. Return ? PromiseResolve(C, x).
   5404 
   5405  // PromiseResolve
   5406  // Step 2. Let promiseCapability be ? NewPromiseCapability(C).
   5407  Rooted<PromiseObject*> promise(
   5408      cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
   5409  if (!promise) {
   5410    return nullptr;
   5411  }
   5412 
   5413  MOZ_ASSERT(promise->state() == JS::PromiseState::Pending);
   5414  MOZ_ASSERT(IsPromiseWithDefaultResolvingFunction(promise));
   5415 
   5416  // PromiseResolve
   5417  // Step 3. Perform ? Call(promiseCapability.[[Resolve]], undefined, « x »).
   5418  if (!ResolvePromiseInternal(cx, promise, value)) {
   5419    return nullptr;
   5420  }
   5421 
   5422  // PromiseResolve
   5423  // Step 4. Return promiseCapability.[[Promise]].
   5424  return promise;
   5425 }
   5426 
   5427 /**
   5428 * https://tc39.es/proposal-promise-try/
   5429 *
   5430 * Promise.try ( )
   5431 */
   5432 static bool Promise_static_try(JSContext* cx, unsigned argc, Value* vp) {
   5433  CallArgs args = CallArgsFromVp(argc, vp);
   5434 
   5435  // 1. Let C be the this value.
   5436  HandleValue cVal = args.thisv();
   5437 
   5438  // 2. If C is not an Object, throw a TypeError exception.
   5439  if (!cVal.isObject()) {
   5440    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   5441                              JSMSG_OBJECT_REQUIRED,
   5442                              "Receiver of Promise.try call");
   5443    return false;
   5444  }
   5445 
   5446  // 3. Let promiseCapability be ? NewPromiseCapability(C).
   5447  RootedObject c(cx, &cVal.toObject());
   5448  Rooted<PromiseCapability> promiseCapability(cx);
   5449  if (!NewPromiseCapability(cx, c, &promiseCapability, false)) {
   5450    return false;
   5451  }
   5452  HandleObject promiseObject = promiseCapability.promise();
   5453 
   5454  // 4. Let status be Completion(Call(callbackfn, undefined, args)).
   5455  size_t argCount = args.length();
   5456  if (argCount > 0) {
   5457    argCount--;
   5458  }
   5459 
   5460  InvokeArgs iargs(cx);
   5461  if (!iargs.init(cx, argCount)) {
   5462    return false;
   5463  }
   5464 
   5465  for (size_t i = 0; i < argCount; i++) {
   5466    iargs[i].set(args[i + 1]);
   5467  }
   5468 
   5469  HandleValue callbackfn = args.get(0);
   5470  RootedValue rval(cx);
   5471  bool ok = Call(cx, callbackfn, UndefinedHandleValue, iargs, &rval);
   5472 
   5473  // 5. If status is an abrupt completion, then
   5474  if (!ok) {
   5475    RootedValue reason(cx);
   5476    Rooted<SavedFrame*> stack(cx);
   5477 
   5478    if (!MaybeGetAndClearExceptionAndStack(cx, &reason, &stack)) {
   5479      return false;
   5480    }
   5481 
   5482    // 5.a. Perform ? Call(promiseCapability.[[Reject]], undefined, «
   5483    // status.[[Value]] »).
   5484    if (!CallPromiseRejectFunction(cx, promiseCapability.reject(), reason,
   5485                                   promiseObject, stack,
   5486                                   UnhandledRejectionBehavior::Report)) {
   5487      return false;
   5488    }
   5489  } else {
   5490    // 6. Else,
   5491    // 6.a. Perform ? Call(promiseCapability.[[Resolve]], undefined, «
   5492    // status.[[Value]] »).
   5493    if (!CallPromiseResolveFunction(cx, promiseCapability.resolve(), rval,
   5494                                    promiseObject)) {
   5495      return false;
   5496    }
   5497  }
   5498 
   5499  // 7. Return promiseCapability.[[Promise]].
   5500  args.rval().setObject(*promiseObject);
   5501  return true;
   5502 }
   5503 
   5504 /**
   5505 * https://tc39.es/proposal-promise-with-resolvers/
   5506 *
   5507 * Promise.withResolvers ( )
   5508 */
   5509 static bool Promise_static_withResolvers(JSContext* cx, unsigned argc,
   5510                                         Value* vp) {
   5511  CallArgs args = CallArgsFromVp(argc, vp);
   5512 
   5513  // Step 1. Let C be the this value.
   5514  HandleValue cVal = args.thisv();
   5515 
   5516  // Step 2. Let promiseCapability be ? NewPromiseCapability(C).
   5517  if (!cVal.isObject()) {
   5518    ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_SEARCH_STACK, cVal,
   5519                     nullptr);
   5520    return false;
   5521  }
   5522  RootedObject c(cx, &cVal.toObject());
   5523  Rooted<PromiseCapability> promiseCapability(cx);
   5524  if (!NewPromiseCapability(cx, c, &promiseCapability, false)) {
   5525    return false;
   5526  }
   5527 
   5528  // Step 3. Let obj be OrdinaryObjectCreate(%Object.prototype%).
   5529  Rooted<PlainObject*> obj(cx, NewPlainObject(cx));
   5530  if (!obj) {
   5531    return false;
   5532  }
   5533 
   5534  // Step 4. Perform ! CreateDataPropertyOrThrow(obj, "promise",
   5535  // promiseCapability.[[Promise]]).
   5536  RootedValue v(cx, ObjectValue(*promiseCapability.promise()));
   5537  if (!NativeDefineDataProperty(cx, obj, cx->names().promise, v,
   5538                                JSPROP_ENUMERATE)) {
   5539    return false;
   5540  }
   5541 
   5542  // Step 5. Perform ! CreateDataPropertyOrThrow(obj, "resolve",
   5543  // promiseCapability.[[Resolve]]).
   5544  v.setObject(*promiseCapability.resolve());
   5545  if (!NativeDefineDataProperty(cx, obj, cx->names().resolve, v,
   5546                                JSPROP_ENUMERATE)) {
   5547    return false;
   5548  }
   5549 
   5550  // Step 6. Perform ! CreateDataPropertyOrThrow(obj, "reject",
   5551  // promiseCapability.[[Reject]]).
   5552  v.setObject(*promiseCapability.reject());
   5553  if (!NativeDefineDataProperty(cx, obj, cx->names().reject, v,
   5554                                JSPROP_ENUMERATE)) {
   5555    return false;
   5556  }
   5557 
   5558  // Step 7. Return obj.
   5559  args.rval().setObject(*obj);
   5560  return true;
   5561 }
   5562 
   5563 /**
   5564 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   5565 *
   5566 * get Promise [ @@species ]
   5567 * https://tc39.es/ecma262/#sec-get-promise-@@species
   5568 */
   5569 bool js::Promise_static_species(JSContext* cx, unsigned argc, Value* vp) {
   5570  CallArgs args = CallArgsFromVp(argc, vp);
   5571 
   5572  // Step 1. Return the this value.
   5573  args.rval().set(args.thisv());
   5574  return true;
   5575 }
   5576 
   5577 enum class HostDefinedDataObjectOption {
   5578  // Allocate the host defined data object, this is the normal operation.
   5579  Allocate,
   5580 
   5581  // Do not allocate the host defined data object because the embeddings can
   5582  // retrieve the same data on its own.
   5583  OptimizeOut,
   5584 
   5585  // Did not allocate the host defined data object because this is a special
   5586  // case used by the debugger.
   5587  UnusedForDebugger,
   5588 };
   5589 
   5590 /**
   5591 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   5592 *
   5593 * PerformPromiseThen ( promise, onFulfilled, onRejected
   5594 *                      [ , resultCapability ] )
   5595 * https://tc39.es/ecma262/#sec-performpromisethen
   5596 *
   5597 * Steps 7-8 for creating PromiseReaction record.
   5598 * We use single object for both fulfillReaction and rejectReaction.
   5599 */
   5600 static PromiseReactionRecord* NewReactionRecord(
   5601    JSContext* cx, Handle<PromiseCapability> resultCapability,
   5602    HandleValue onFulfilled, HandleValue onRejected,
   5603    HostDefinedDataObjectOption hostDefinedDataObjectOption) {
   5604 #ifdef DEBUG
   5605  if (resultCapability.promise()) {
   5606    if (hostDefinedDataObjectOption == HostDefinedDataObjectOption::Allocate) {
   5607      if (resultCapability.promise()->is<PromiseObject>()) {
   5608        // If `resultCapability.promise` is a Promise object,
   5609        // `resultCapability.{resolve,reject}` may be optimized out,
   5610        // but if they're not, they should be callable.
   5611        MOZ_ASSERT_IF(resultCapability.resolve(),
   5612                      IsCallable(resultCapability.resolve()));
   5613        MOZ_ASSERT_IF(resultCapability.reject(),
   5614                      IsCallable(resultCapability.reject()));
   5615      } else {
   5616        // If `resultCapability.promise` is a non-Promise object
   5617        // (including wrapped Promise object),
   5618        // `resultCapability.{resolve,reject}` should be callable.
   5619        MOZ_ASSERT(resultCapability.resolve());
   5620        MOZ_ASSERT(IsCallable(resultCapability.resolve()));
   5621        MOZ_ASSERT(resultCapability.reject());
   5622        MOZ_ASSERT(IsCallable(resultCapability.reject()));
   5623      }
   5624    } else if (hostDefinedDataObjectOption ==
   5625               HostDefinedDataObjectOption::UnusedForDebugger) {
   5626      // For debugger usage, `resultCapability.promise` should be a
   5627      // maybe-wrapped Promise object. The other fields are not used.
   5628      //
   5629      // This is the only case where we allow `resolve` and `reject` to
   5630      // be null when the `promise` field is not a PromiseObject.
   5631      JSObject* unwrappedPromise = UncheckedUnwrap(resultCapability.promise());
   5632      MOZ_ASSERT(unwrappedPromise->is<PromiseObject>() ||
   5633                 JS_IsDeadWrapper(unwrappedPromise));
   5634      MOZ_ASSERT(!resultCapability.resolve());
   5635      MOZ_ASSERT(!resultCapability.reject());
   5636    }
   5637  } else {
   5638    // `resultCapability.promise` is null for the following cases:
   5639    //   * resulting Promise is known to be unused
   5640    //   * Async Function
   5641    //   * Async Generator
   5642    // In any case, other fields are also not used.
   5643    MOZ_ASSERT(!resultCapability.resolve());
   5644    MOZ_ASSERT(!resultCapability.reject());
   5645    MOZ_ASSERT(hostDefinedDataObjectOption !=
   5646               HostDefinedDataObjectOption::UnusedForDebugger);
   5647  }
   5648 #endif
   5649 
   5650  // Ensure the onFulfilled handler has the expected type.
   5651  MOZ_ASSERT(onFulfilled.isInt32() || onFulfilled.isObjectOrNull());
   5652  MOZ_ASSERT_IF(onFulfilled.isObject(), IsCallable(onFulfilled));
   5653  MOZ_ASSERT_IF(onFulfilled.isInt32(),
   5654                0 <= onFulfilled.toInt32() &&
   5655                    onFulfilled.toInt32() < int32_t(PromiseHandler::Limit));
   5656 
   5657  // Ensure the onRejected handler has the expected type.
   5658  MOZ_ASSERT(onRejected.isInt32() || onRejected.isObjectOrNull());
   5659  MOZ_ASSERT_IF(onRejected.isObject(), IsCallable(onRejected));
   5660  MOZ_ASSERT_IF(onRejected.isInt32(),
   5661                0 <= onRejected.toInt32() &&
   5662                    onRejected.toInt32() < int32_t(PromiseHandler::Limit));
   5663 
   5664  // Handlers must either both be present or both be absent.
   5665  MOZ_ASSERT(onFulfilled.isNull() == onRejected.isNull());
   5666 
   5667  RootedObject hostDefinedData(cx);
   5668  if (hostDefinedDataObjectOption == HostDefinedDataObjectOption::Allocate) {
   5669    if (!GetObjectFromHostDefinedData(cx, &hostDefinedData)) {
   5670      return nullptr;
   5671    }
   5672  }
   5673 
   5674  PromiseReactionRecord* reaction =
   5675      NewBuiltinClassInstance<PromiseReactionRecord>(cx);
   5676  if (!reaction) {
   5677    return nullptr;
   5678  }
   5679  cx->check(resultCapability.promise(), onFulfilled, onRejected,
   5680            resultCapability.resolve(), resultCapability.reject(),
   5681            hostDefinedData);
   5682 
   5683  // Step 7. Let fulfillReaction be the PromiseReaction
   5684  //         { [[Capability]]: resultCapability, [[Type]]: Fulfill,
   5685  //           [[Handler]]: onFulfilledJobCallback }.
   5686  // Step 8. Let rejectReaction be the PromiseReaction
   5687  //         { [[Capability]]: resultCapability, [[Type]]: Reject,
   5688  //           [[Handler]]: onRejectedJobCallback }.
   5689 
   5690  // See comments for ReactionRecordSlots for the relation between
   5691  // spec record fields and PromiseReactionRecord slots.
   5692  reaction->initFixedSlot(PromiseReactionRecord::Promise,
   5693                          ObjectOrNullValue(resultCapability.promise()));
   5694  // We set [[Type]] in EnqueuePromiseReactionJob, by calling
   5695  // setTargetStateAndHandlerArg.
   5696  reaction->initFixedSlot(PromiseReactionRecord::Flags, Int32Value(0));
   5697  reaction->initFixedSlot(PromiseReactionRecord::OnFulfilled, onFulfilled);
   5698  reaction->initFixedSlot(PromiseReactionRecord::OnRejected, onRejected);
   5699  reaction->initFixedSlot(PromiseReactionRecord::Resolve,
   5700                          ObjectOrNullValue(resultCapability.resolve()));
   5701  reaction->initFixedSlot(PromiseReactionRecord::Reject,
   5702                          ObjectOrNullValue(resultCapability.reject()));
   5703  reaction->initFixedSlot(PromiseReactionRecord::HostDefinedData,
   5704                          ObjectOrNullValue(hostDefinedData));
   5705 
   5706  return reaction;
   5707 }
   5708 
   5709 static bool IsPromiseSpecies(JSContext* cx, JSFunction* species) {
   5710  return species->maybeNative() == Promise_static_species;
   5711 }
   5712 
   5713 // Whether to create a promise as the return value of Promise#{then,catch}.
   5714 // If the return value is known to be unused, and if the operation is known
   5715 // to be unobservable, we can skip creating the promise.
   5716 enum class CreateDependentPromise { Always, SkipIfCtorUnobservable };
   5717 
   5718 /**
   5719 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   5720 *
   5721 * Promise.prototype.then ( onFulfilled, onRejected )
   5722 * https://tc39.es/ecma262/#sec-promise.prototype.then
   5723 *
   5724 * Steps 3-4.
   5725 */
   5726 static bool PromiseThenNewPromiseCapability(
   5727    JSContext* cx, HandleObject promiseObj,
   5728    CreateDependentPromise createDependent,
   5729    MutableHandle<PromiseCapability> resultCapability) {
   5730  // Step 3. Let C be ? SpeciesConstructor(promise, %Promise%).
   5731  RootedObject C(cx, SpeciesConstructor(cx, promiseObj, JSProto_Promise,
   5732                                        IsPromiseSpecies));
   5733  if (!C) {
   5734    return false;
   5735  }
   5736 
   5737  if (createDependent != CreateDependentPromise::Always &&
   5738      IsNativeFunction(C, PromiseConstructor)) {
   5739    return true;
   5740  }
   5741 
   5742  // Step 4. Let resultCapability be ? NewPromiseCapability(C).
   5743  if (!NewPromiseCapability(cx, C, resultCapability, true)) {
   5744    return false;
   5745  }
   5746 
   5747  JSObject* unwrappedPromise = promiseObj;
   5748  if (IsWrapper(promiseObj)) {
   5749    unwrappedPromise = UncheckedUnwrap(promiseObj);
   5750  }
   5751  JSObject* unwrappedNewPromise = resultCapability.promise();
   5752  if (IsWrapper(resultCapability.promise())) {
   5753    unwrappedNewPromise = UncheckedUnwrap(resultCapability.promise());
   5754  }
   5755  if (unwrappedPromise->is<PromiseObject>() &&
   5756      unwrappedNewPromise->is<PromiseObject>()) {
   5757    unwrappedNewPromise->as<PromiseObject>().copyUserInteractionFlagsFrom(
   5758        unwrappedPromise->as<PromiseObject>());
   5759  }
   5760 
   5761  return true;
   5762 }
   5763 
   5764 /**
   5765 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   5766 *
   5767 * Promise.prototype.then ( onFulfilled, onRejected )
   5768 * https://tc39.es/ecma262/#sec-promise.prototype.then
   5769 *
   5770 * Steps 3-5.
   5771 */
   5772 [[nodiscard]] PromiseObject* js::OriginalPromiseThen(JSContext* cx,
   5773                                                     HandleObject promiseObj,
   5774                                                     HandleObject onFulfilled,
   5775                                                     HandleObject onRejected) {
   5776  cx->check(promiseObj, onFulfilled, onRejected);
   5777 
   5778  RootedValue promiseVal(cx, ObjectValue(*promiseObj));
   5779  Rooted<PromiseObject*> unwrappedPromise(
   5780      cx,
   5781      UnwrapAndTypeCheckValue<PromiseObject>(cx, promiseVal, [cx, promiseObj] {
   5782        JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
   5783                                   JSMSG_INCOMPATIBLE_PROTO, "Promise", "then",
   5784                                   promiseObj->getClass()->name);
   5785      }));
   5786  if (!unwrappedPromise) {
   5787    return nullptr;
   5788  }
   5789 
   5790  // Step 3. Let C be ? SpeciesConstructor(promise, %Promise%).
   5791  // Step 4. Let resultCapability be ? NewPromiseCapability(C).
   5792  Rooted<PromiseObject*> newPromise(
   5793      cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
   5794  if (!newPromise) {
   5795    return nullptr;
   5796  }
   5797  newPromise->copyUserInteractionFlagsFrom(*unwrappedPromise);
   5798 
   5799  Rooted<PromiseCapability> resultCapability(cx);
   5800  resultCapability.promise().set(newPromise);
   5801 
   5802  // Step 5. Return PerformPromiseThen(promise, onFulfilled, onRejected,
   5803  //                                   resultCapability).
   5804  {
   5805    RootedValue onFulfilledVal(cx, ObjectOrNullValue(onFulfilled));
   5806    RootedValue onRejectedVal(cx, ObjectOrNullValue(onRejected));
   5807    if (!PerformPromiseThen(cx, unwrappedPromise, onFulfilledVal, onRejectedVal,
   5808                            resultCapability)) {
   5809      return nullptr;
   5810    }
   5811  }
   5812 
   5813  return newPromise;
   5814 }
   5815 
   5816 /**
   5817 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   5818 *
   5819 * Promise.prototype.then ( onFulfilled, onRejected )
   5820 * https://tc39.es/ecma262/#sec-promise.prototype.then
   5821 *
   5822 * Steps 3-5.
   5823 */
   5824 [[nodiscard]] static bool OriginalPromiseThenWithoutSettleHandlers(
   5825    JSContext* cx, Handle<PromiseObject*> promise,
   5826    Handle<PromiseObject*> promiseToResolve) {
   5827  cx->check(promise);
   5828 
   5829  // Step 3. Let C be ? SpeciesConstructor(promise, %Promise%).
   5830  // Step 4. Let resultCapability be ? NewPromiseCapability(C).
   5831  Rooted<PromiseCapability> resultCapability(cx);
   5832  if (!PromiseThenNewPromiseCapability(
   5833          cx, promise, CreateDependentPromise::SkipIfCtorUnobservable,
   5834          &resultCapability)) {
   5835    return false;
   5836  }
   5837 
   5838  // Step 5. Return PerformPromiseThen(promise, onFulfilled, onRejected,
   5839  //                                   resultCapability).
   5840  return PerformPromiseThenWithoutSettleHandlers(cx, promise, promiseToResolve,
   5841                                                 resultCapability);
   5842 }
   5843 
   5844 [[nodiscard]] static bool PerformPromiseThenWithReaction(
   5845    JSContext* cx, Handle<PromiseObject*> promise,
   5846    Handle<PromiseReactionRecord*> reaction);
   5847 
   5848 [[nodiscard]] bool js::ReactToUnwrappedPromise(
   5849    JSContext* cx, Handle<PromiseObject*> unwrappedPromise,
   5850    HandleObject onFulfilled_, HandleObject onRejected_,
   5851    UnhandledRejectionBehavior behavior) {
   5852  cx->check(onFulfilled_, onRejected_);
   5853 
   5854  MOZ_ASSERT_IF(onFulfilled_, IsCallable(onFulfilled_));
   5855  MOZ_ASSERT_IF(onRejected_, IsCallable(onRejected_));
   5856 
   5857  RootedValue onFulfilled(
   5858      cx, onFulfilled_ ? ObjectValue(*onFulfilled_)
   5859                       : Int32Value(int32_t(PromiseHandler::Identity)));
   5860 
   5861  RootedValue onRejected(
   5862      cx, onRejected_ ? ObjectValue(*onRejected_)
   5863                      : Int32Value(int32_t(PromiseHandler::Thrower)));
   5864 
   5865  Rooted<PromiseCapability> resultCapability(cx);
   5866  MOZ_ASSERT(!resultCapability.promise());
   5867 
   5868  auto hostDefinedDataObjectOption =
   5869      unwrappedPromise->state() == JS::PromiseState::Pending
   5870          ? HostDefinedDataObjectOption::Allocate
   5871          : HostDefinedDataObjectOption::OptimizeOut;
   5872 
   5873  Rooted<PromiseReactionRecord*> reaction(
   5874      cx, NewReactionRecord(cx, resultCapability, onFulfilled, onRejected,
   5875                            hostDefinedDataObjectOption));
   5876  if (!reaction) {
   5877    return false;
   5878  }
   5879 
   5880  if (behavior == UnhandledRejectionBehavior::Ignore) {
   5881    reaction->setShouldIgnoreUnhandledRejection();
   5882  }
   5883 
   5884  return PerformPromiseThenWithReaction(cx, unwrappedPromise, reaction);
   5885 }
   5886 
   5887 static bool CanCallOriginalPromiseThenBuiltin(JSContext* cx,
   5888                                              HandleValue promise) {
   5889  return promise.isObject() && promise.toObject().is<PromiseObject>() &&
   5890         IsPromiseWithDefaultProperties(&promise.toObject().as<PromiseObject>(),
   5891                                        cx);
   5892 }
   5893 
   5894 static MOZ_ALWAYS_INLINE bool IsPromiseThenOrCatchRetValImplicitlyUsed(
   5895    JSContext* cx, PromiseObject* promise) {
   5896  // Embedding requires the return value of then/catch as
   5897  // `enqueuePromiseJob` parameter, to propaggate the user-interaction.
   5898  // We cannot optimize out the return value if the flag is set by embedding.
   5899  if (promise->requiresUserInteractionHandling()) {
   5900    return true;
   5901  }
   5902 
   5903  // The returned promise of Promise#then and Promise#catch contains
   5904  // stack info if async stack is enabled.  Even if their return value is not
   5905  // used explicitly in the script, the stack info is observable in devtools
   5906  // and profilers.  We shouldn't apply the optimization not to allocate the
   5907  // returned Promise object if the it's implicitly used by them.
   5908  if (!cx->options().asyncStack()) {
   5909    return false;
   5910  }
   5911 
   5912  // If devtools is opened, the current realm will become debuggee.
   5913  if (cx->realm()->isDebuggee()) {
   5914    return true;
   5915  }
   5916 
   5917  // There are 2 profilers, and they can be independently enabled.
   5918  if (cx->runtime()->geckoProfiler().enabled()) {
   5919    return true;
   5920  }
   5921  if (JS::IsProfileTimelineRecordingEnabled()) {
   5922    return true;
   5923  }
   5924 
   5925  // The stack is also observable from Error#stack, but we don't care since
   5926  // it's nonstandard feature.
   5927  return false;
   5928 }
   5929 
   5930 /**
   5931 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   5932 *
   5933 * Promise.prototype.then ( onFulfilled, onRejected )
   5934 * https://tc39.es/ecma262/#sec-promise.prototype.then
   5935 *
   5936 * Steps 3-5.
   5937 */
   5938 static bool OriginalPromiseThenBuiltin(JSContext* cx, HandleValue promiseVal,
   5939                                       HandleValue onFulfilled,
   5940                                       HandleValue onRejected,
   5941                                       MutableHandleValue rval,
   5942                                       bool rvalExplicitlyUsed) {
   5943  cx->check(promiseVal, onFulfilled, onRejected);
   5944  MOZ_ASSERT(CanCallOriginalPromiseThenBuiltin(cx, promiseVal));
   5945 
   5946  Rooted<PromiseObject*> promise(cx,
   5947                                 &promiseVal.toObject().as<PromiseObject>());
   5948 
   5949  bool rvalUsed = rvalExplicitlyUsed ||
   5950                  IsPromiseThenOrCatchRetValImplicitlyUsed(cx, promise);
   5951 
   5952  // Step 3. Let C be ? SpeciesConstructor(promise, %Promise%).
   5953  // Step 4. Let resultCapability be ? NewPromiseCapability(C).
   5954  Rooted<PromiseCapability> resultCapability(cx);
   5955  if (rvalUsed) {
   5956    PromiseObject* resultPromise =
   5957        CreatePromiseObjectWithoutResolutionFunctions(cx);
   5958    if (!resultPromise) {
   5959      return false;
   5960    }
   5961 
   5962    resultPromise->copyUserInteractionFlagsFrom(
   5963        promiseVal.toObject().as<PromiseObject>());
   5964    resultCapability.promise().set(resultPromise);
   5965  }
   5966 
   5967  // Step 5. Return PerformPromiseThen(promise, onFulfilled, onRejected,
   5968  //                                   resultCapability).
   5969  if (!PerformPromiseThen(cx, promise, onFulfilled, onRejected,
   5970                          resultCapability)) {
   5971    return false;
   5972  }
   5973 
   5974  if (rvalUsed) {
   5975    rval.setObject(*resultCapability.promise());
   5976  } else {
   5977    rval.setUndefined();
   5978  }
   5979  return true;
   5980 }
   5981 
   5982 [[nodiscard]] bool js::RejectPromiseWithPendingError(
   5983    JSContext* cx, Handle<PromiseObject*> promise) {
   5984  cx->check(promise);
   5985 
   5986  if (!cx->isExceptionPending()) {
   5987    // Reject the promise, but also propagate this uncatchable error.
   5988    (void)PromiseObject::reject(cx, promise, UndefinedHandleValue);
   5989    return false;
   5990  }
   5991 
   5992  RootedValue exn(cx);
   5993  if (!GetAndClearException(cx, &exn)) {
   5994    return false;
   5995  }
   5996  return PromiseObject::reject(cx, promise, exn);
   5997 }
   5998 
   5999 // Some async/await functions are implemented here instead of
   6000 // js/src/builtin/AsyncFunction.cpp, to call Promise internal functions.
   6001 
   6002 /**
   6003 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   6004 *
   6005 * Runtime Semantics: EvaluateAsyncFunctionBody
   6006 * AsyncFunctionBody : FunctionBody
   6007 * https://tc39.es/ecma262/#sec-runtime-semantics-evaluateasyncfunctionbody
   6008 *
   6009 * Runtime Semantics: EvaluateAsyncConciseBody
   6010 * AsyncConciseBody : ExpressionBody
   6011 * https://tc39.es/ecma262/#sec-runtime-semantics-evaluateasyncconcisebody
   6012 */
   6013 [[nodiscard]] PromiseObject* js::CreatePromiseObjectForAsync(JSContext* cx) {
   6014  // Step 1. Let promiseCapability be ! NewPromiseCapability(%Promise%).
   6015  PromiseObject* promise = CreatePromiseObjectWithoutResolutionFunctions(cx);
   6016  if (!promise) {
   6017    return nullptr;
   6018  }
   6019 
   6020  AddPromiseFlags(*promise, PROMISE_FLAG_ASYNC);
   6021  return promise;
   6022 }
   6023 
   6024 bool js::IsPromiseForAsyncFunctionOrGenerator(JSObject* promise) {
   6025  return promise->is<PromiseObject>() &&
   6026         PromiseHasAnyFlag(promise->as<PromiseObject>(), PROMISE_FLAG_ASYNC);
   6027 }
   6028 
   6029 [[nodiscard]] PromiseObject* js::CreatePromiseObjectForAsyncGenerator(
   6030    JSContext* cx) {
   6031  PromiseObject* promise = CreatePromiseObjectWithoutResolutionFunctions(cx);
   6032  if (!promise) {
   6033    return nullptr;
   6034  }
   6035 
   6036  AddPromiseFlags(*promise, PROMISE_FLAG_ASYNC);
   6037  return promise;
   6038 }
   6039 
   6040 /**
   6041 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   6042 *
   6043 * AsyncFunctionStart ( promiseCapability, asyncFunctionBody )
   6044 * https://tc39.es/ecma262/#sec-async-functions-abstract-operations-async-function-start
   6045 *
   6046 * Steps 4.f-g.
   6047 */
   6048 [[nodiscard]] bool js::AsyncFunctionThrown(
   6049    JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue reason,
   6050    JS::Handle<SavedFrame*> unwrappedRejectionStack) {
   6051  if (resultPromise->state() != JS::PromiseState::Pending) {
   6052    // OOM after resolving promise.
   6053    // Report a warning and ignore the result.
   6054    if (!WarnNumberASCII(cx, JSMSG_UNHANDLABLE_PROMISE_REJECTION_WARNING)) {
   6055      if (cx->isExceptionPending()) {
   6056        cx->clearPendingException();
   6057      }
   6058    }
   6059    return true;
   6060  }
   6061 
   6062  // Step 4.f. Else,
   6063  // Step 4.f.i. Assert: result.[[Type]] is throw.
   6064  // Step 4.f.ii. Perform
   6065  //              ! Call(promiseCapability.[[Reject]], undefined,
   6066  //                 « result.[[Value]] »).
   6067  // Step 4.g. Return.
   6068  return RejectPromiseInternal(cx, resultPromise, reason,
   6069                               unwrappedRejectionStack);
   6070 }
   6071 
   6072 /**
   6073 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   6074 *
   6075 * AsyncFunctionStart ( promiseCapability, asyncFunctionBody )
   6076 * https://tc39.es/ecma262/#sec-async-functions-abstract-operations-async-function-start
   6077 *
   6078 * Steps 4.e, 4.g.
   6079 */
   6080 [[nodiscard]] bool js::AsyncFunctionReturned(
   6081    JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value) {
   6082  // Step 4.e. Else if result.[[Type]] is return, then
   6083  // Step 4.e.i. Perform
   6084  //             ! Call(promiseCapability.[[Resolve]], undefined,
   6085  //                    « result.[[Value]] »).
   6086  return ResolvePromiseInternal(cx, resultPromise, value);
   6087 }
   6088 
   6089 /**
   6090 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   6091 *
   6092 * Await
   6093 * https://tc39.github.io/ecma262/#await
   6094 *
   6095 * Helper function that performs Await(promise) steps 2-7.
   6096 * The same steps are also used in a few other places in the spec.
   6097 */
   6098 template <typename T>
   6099 [[nodiscard]] static bool InternalAwait(JSContext* cx, HandleValue value,
   6100                                        HandleObject resultPromise,
   6101                                        PromiseHandler onFulfilled,
   6102                                        PromiseHandler onRejected,
   6103                                        T extraStep) {
   6104  // Step 2. Let promise be ? PromiseResolve(%Promise%, value).
   6105  RootedObject promise(cx, PromiseObject::unforgeableResolve(cx, value));
   6106  if (!promise) {
   6107    return false;
   6108  }
   6109 
   6110  // This downcast is safe because unforgeableResolve either returns `value`
   6111  // (only if it is already a possibly-wrapped promise) or creates a new
   6112  // promise using the Promise constructor.
   6113  Rooted<PromiseObject*> unwrappedPromise(
   6114      cx, UnwrapAndDowncastObject<PromiseObject>(cx, promise));
   6115  if (!unwrappedPromise) {
   6116    return false;
   6117  }
   6118 
   6119  // Steps 3-6 for creating onFulfilled/onRejected are done by caller.
   6120 
   6121  // Step 7. Perform ! PerformPromiseThen(promise, onFulfilled, onRejected).
   6122  RootedValue onFulfilledValue(cx, Int32Value(int32_t(onFulfilled)));
   6123  RootedValue onRejectedValue(cx, Int32Value(int32_t(onRejected)));
   6124  Rooted<PromiseCapability> resultCapability(cx);
   6125  resultCapability.promise().set(resultPromise);
   6126 
   6127  auto hostDefinedDataObjectOption =
   6128      unwrappedPromise->state() == JS::PromiseState::Pending
   6129          ? HostDefinedDataObjectOption::Allocate
   6130          : HostDefinedDataObjectOption::OptimizeOut;
   6131 
   6132  Rooted<PromiseReactionRecord*> reaction(
   6133      cx, NewReactionRecord(cx, resultCapability, onFulfilledValue,
   6134                            onRejectedValue, hostDefinedDataObjectOption));
   6135  if (!reaction) {
   6136    return false;
   6137  }
   6138  extraStep(reaction);
   6139  return PerformPromiseThenWithReaction(cx, unwrappedPromise, reaction);
   6140 }
   6141 
   6142 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
   6143 // Explicit Resource Management Proposal
   6144 // 27.1.3.1 %AsyncIteratorPrototype% [ @@asyncDispose ] ( )
   6145 // Steps 6.c-g
   6146 // https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-%25asynciteratorprototype%25-%40%40asyncdispose
   6147 // The steps mentioned above are almost identical to the steps 3-7 of
   6148 // https://tc39.es/ecma262/#await we have a utility function InternalAwait which
   6149 // covers these steps thus this following function wraps around the utility
   6150 // and implements the steps of %AsyncIteratorPrototype% [ @@asyncDispose ] ( ).
   6151 [[nodiscard]] bool js::InternalAsyncIteratorDisposeAwait(
   6152    JSContext* cx, JS::Handle<JS::Value> value,
   6153    JS::Handle<JSObject*> resultPromise) {
   6154  auto extra = [](JS::Handle<PromiseReactionRecord*> reaction) {};
   6155  return InternalAwait(cx, value, resultPromise,
   6156                       PromiseHandler::AsyncIteratorDisposeAwaitFulfilled,
   6157                       PromiseHandler::Thrower, extra);
   6158 }
   6159 #endif
   6160 
   6161 [[nodiscard]] bool js::InternalAsyncGeneratorAwait(
   6162    JSContext* cx, JS::Handle<AsyncGeneratorObject*> generator,
   6163    JS::Handle<JS::Value> value, PromiseHandler onFulfilled,
   6164    PromiseHandler onRejected) {
   6165  auto extra = [&](Handle<PromiseReactionRecord*> reaction) {
   6166    reaction->setIsAsyncGenerator(generator);
   6167  };
   6168  return InternalAwait(cx, value, nullptr, onFulfilled, onRejected, extra);
   6169 }
   6170 
   6171 /**
   6172 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   6173 *
   6174 * Await
   6175 * https://tc39.es/ecma262/#await
   6176 */
   6177 [[nodiscard]] JSObject* js::AsyncFunctionAwait(
   6178    JSContext* cx, Handle<AsyncFunctionGeneratorObject*> genObj,
   6179    HandleValue value) {
   6180  auto extra = [&](Handle<PromiseReactionRecord*> reaction) {
   6181    MOZ_ASSERT(genObj->realm() == reaction->realm());
   6182    MOZ_ASSERT(genObj->realm() == cx->realm());
   6183    reaction->setIsAsyncFunction(genObj);
   6184  };
   6185  if (!InternalAwait(cx, value, nullptr,
   6186                     PromiseHandler::AsyncFunctionAwaitedFulfilled,
   6187                     PromiseHandler::AsyncFunctionAwaitedRejected, extra)) {
   6188    return nullptr;
   6189  }
   6190  return genObj->promise();
   6191 }
   6192 
   6193 /**
   6194 * ES2026 draft rev d14670224281909f5bb552e8ebe4a8e958646c16
   6195 *
   6196 * %AsyncFromSyncIteratorPrototype%.next ( [ value ] )
   6197 * https://tc39.es/ecma262/#sec-%asyncfromsynciteratorprototype%.next
   6198 *
   6199 * %AsyncFromSyncIteratorPrototype%.return ( [ value ] )
   6200 * https://tc39.es/ecma262/#sec-%asyncfromsynciteratorprototype%.return
   6201 *
   6202 * %AsyncFromSyncIteratorPrototype%.throw ( [ value ] )
   6203 * https://tc39.es/ecma262/#sec-%asyncfromsynciteratorprototype%.throw
   6204 *
   6205 * AsyncFromSyncIteratorContinuation ( result, promiseCapability,
   6206 *                                     syncIteratorRecord, closeOnRejection )
   6207 * https://tc39.es/ecma262/#sec-asyncfromsynciteratorcontinuation
   6208 */
   6209 bool js::AsyncFromSyncIteratorMethod(JSContext* cx, CallArgs& args,
   6210                                     CompletionKind completionKind) {
   6211  // Step 1. Let O be the this value.
   6212  HandleValue thisVal = args.thisv();
   6213 
   6214  // Step 2. Assert: O is an Object that has a [[SyncIteratorRecord]] internal
   6215  //         slot.
   6216  MOZ_ASSERT(thisVal.isObject());
   6217  MOZ_ASSERT(thisVal.toObject().is<AsyncFromSyncIteratorObject>());
   6218 
   6219  // Step 3. Let promiseCapability be ! NewPromiseCapability(%Promise%).
   6220  Rooted<PromiseObject*> resultPromise(
   6221      cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
   6222  if (!resultPromise) {
   6223    return false;
   6224  }
   6225 
   6226  Rooted<AsyncFromSyncIteratorObject*> asyncIter(
   6227      cx, &thisVal.toObject().as<AsyncFromSyncIteratorObject>());
   6228 
   6229  // next():
   6230  // Step 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]].
   6231  //
   6232  // or
   6233  //
   6234  // return() / throw():
   6235  // Step 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]].
   6236  // Step 5. Let syncIterator be syncIteratorRecord.[[Iterator]].
   6237  RootedObject iter(cx, asyncIter->iterator());
   6238 
   6239  RootedValue func(cx);
   6240  if (completionKind == CompletionKind::Normal) {
   6241    // next() preparing for steps 5-6.
   6242    func.set(asyncIter->nextMethod());
   6243  } else if (completionKind == CompletionKind::Return) {
   6244    // return() steps 6-8.
   6245    // Step 6. Let return be Completion(GetMethod(syncIterator, "return")).
   6246    // Step 7. IfAbruptRejectPromise(return, promiseCapability).
   6247    if (!GetProperty(cx, iter, iter, cx->names().return_, &func)) {
   6248      return AbruptRejectPromise(cx, args, resultPromise, nullptr);
   6249    }
   6250 
   6251    // Step 8. If return is undefined, then
   6252    // (Note: GetMethod contains a step that changes `null` to `undefined`;
   6253    // we omit that step above, and check for `null` here instead.)
   6254    if (func.isNullOrUndefined()) {
   6255      // Step 8.a. Let iterResult be CreateIterResultObject(value, true).
   6256      PlainObject* resultObj = CreateIterResultObject(cx, args.get(0), true);
   6257      if (!resultObj) {
   6258        return AbruptRejectPromise(cx, args, resultPromise, nullptr);
   6259      }
   6260 
   6261      RootedValue resultVal(cx, ObjectValue(*resultObj));
   6262 
   6263      // Step 8.b. Perform ! Call(promiseCapability.[[Resolve]], undefined,
   6264      //                          « iterResult »).
   6265      if (!ResolvePromiseInternal(cx, resultPromise, resultVal)) {
   6266        return AbruptRejectPromise(cx, args, resultPromise, nullptr);
   6267      }
   6268 
   6269      // Step 8.c. Return promiseCapability.[[Promise]].
   6270      args.rval().setObject(*resultPromise);
   6271      return true;
   6272    }
   6273  } else {
   6274    // throw() steps 6-8.
   6275    MOZ_ASSERT(completionKind == CompletionKind::Throw);
   6276 
   6277    // Step 6. Let throw be Completion(GetMethod(syncIterator, "throw")).
   6278    // Step 7. IfAbruptRejectPromise(throw, promiseCapability).
   6279    if (!GetProperty(cx, iter, iter, cx->names().throw_, &func)) {
   6280      return AbruptRejectPromise(cx, args, resultPromise, nullptr);
   6281    }
   6282 
   6283    // Step 8. If throw is undefined, then
   6284    // (Note: GetMethod contains a step that changes `null` to `undefined`;
   6285    // we omit that step above, and check for `null` here instead.)
   6286    if (func.isNullOrUndefined()) {
   6287      // Step 8.a. NOTE: If syncIterator does not have a throw method, close it
   6288      //           to give it a chance to clean up before we reject the
   6289      //           capability.
   6290      // Step 8.b. Let closeCompletion be NormalCompletion(empty).
   6291      // Step 8.c. Let result be Completion(IteratorClose(syncIteratorRecord,
   6292      //           closeCompletion)).
   6293      // Step 8.d. IfAbruptRejectPromise(result, promiseCapability).
   6294      if (!CloseIterOperation(cx, iter, CompletionKind::Normal)) {
   6295        return AbruptRejectPromise(cx, args, resultPromise, nullptr);
   6296      }
   6297 
   6298      // Step 8.e. NOTE: The next step throws a TypeError to indicate that there
   6299      //           was a protocol violation: syncIterator does not have a throw
   6300      //           method.
   6301      // Step 8.f. NOTE: If closing syncIterator does not throw then the result
   6302      //           of that operation is ignored, even if it yields a rejected
   6303      //           promise.
   6304      // Step 8.g. Perform ! Call(_promiseCapability_.[[Reject]], *undefined*,
   6305      //           « a newly created *TypeError* object »).
   6306      Rooted<Value> noThrowMethodError(cx);
   6307      if (!GetTypeError(cx, JSMSG_ITERATOR_NO_THROW, &noThrowMethodError)) {
   6308        return AbruptRejectPromise(cx, args, resultPromise, nullptr);
   6309      }
   6310      if (!RejectPromiseInternal(cx, resultPromise, noThrowMethodError)) {
   6311        return AbruptRejectPromise(cx, args, resultPromise, nullptr);
   6312      }
   6313 
   6314      // Step 8.h. Return promiseCapability.[[Promise]].
   6315      args.rval().setObject(*resultPromise);
   6316      return true;
   6317    }
   6318  }
   6319 
   6320  // next():
   6321  // Step 5. If value is present, then
   6322  // Step 5.a. Let result be Completion(IteratorNext(syncIteratorRecord,
   6323  //                                                 value)).
   6324  // Step 6. Else,
   6325  // Step 6.a. Let result be Completion(IteratorNext(syncIteratorRecord)).
   6326  //
   6327  // or
   6328  //
   6329  // return():
   6330  // Step 9. If value is present, then
   6331  // Step 9.a. Let result be Completion(Call(return, syncIterator,
   6332  //                                         « value »)).
   6333  // Step 10. Else,
   6334  // Step 10.a. Let result be Completion(Call(return, syncIterator)).
   6335  //
   6336  // throw():
   6337  // Step 9. If value is present, then
   6338  // Step 9.a. Let result be Completion(Call(throw, syncIterator,
   6339  //                                         « value »)).
   6340  // Step 10. Else,
   6341  // Step 10.a. Let result be Completion(Call(throw, syncIterator)).
   6342  RootedValue iterVal(cx, ObjectValue(*iter));
   6343  RootedValue resultVal(cx);
   6344  bool ok;
   6345  if (args.length() == 0) {
   6346    ok = Call(cx, func, iterVal, &resultVal);
   6347  } else {
   6348    ok = Call(cx, func, iterVal, args[0], &resultVal);
   6349  }
   6350  if (!ok) {
   6351    // next():
   6352    // Step 7. IfAbruptRejectPromise(result, promiseCapability).
   6353    //
   6354    // return() / throw():
   6355    // Step 11. IfAbruptRejectPromise(result, promiseCapability).
   6356    return AbruptRejectPromise(cx, args, resultPromise, nullptr);
   6357  }
   6358 
   6359  // next() steps 5-6 -> IteratorNext:
   6360  // Step 5. If result is not an Object, throw a TypeError exception.
   6361  // next():
   6362  // Step 7. IfAbruptRejectPromise(result, promiseCapability).
   6363  //
   6364  // or
   6365  //
   6366  // return() / throw():
   6367  // Step 12. If result is not an Object, then
   6368  // Step 12.a. Perform ! Call(promiseCapability.[[Reject]], undefined,
   6369  //                           « a newly created TypeError object »).
   6370  // Step 12.b. Return promiseCapability.[[Promise]].
   6371  if (!resultVal.isObject()) {
   6372    CheckIsObjectKind kind;
   6373    switch (completionKind) {
   6374      case CompletionKind::Normal:
   6375        kind = CheckIsObjectKind::IteratorNext;
   6376        break;
   6377      case CompletionKind::Throw:
   6378        kind = CheckIsObjectKind::IteratorThrow;
   6379        break;
   6380      case CompletionKind::Return:
   6381        kind = CheckIsObjectKind::IteratorReturn;
   6382        break;
   6383    }
   6384    MOZ_ALWAYS_FALSE(ThrowCheckIsObject(cx, kind));
   6385    return AbruptRejectPromise(cx, args, resultPromise, nullptr);
   6386  }
   6387 
   6388  RootedObject resultObj(cx, &resultVal.toObject());
   6389 
   6390  // next():
   6391  // Step 8. Return AsyncFromSyncIteratorContinuation(result,
   6392  //                                                  promiseCapability,
   6393  //                                                  syncIteratorRecord,
   6394  //                                                  true).
   6395  //
   6396  // return():
   6397  // Step 13. Return AsyncFromSyncIteratorContinuation(result,
   6398  //                                                   promiseCapability,
   6399  //                                                   syncIteratorRecord,
   6400  //                                                   false).
   6401  //
   6402  // throw():
   6403  // Step 13. Return AsyncFromSyncIteratorContinuation(result,
   6404  //                                                   promiseCapability,
   6405  //                                                   syncIteratorRecord,
   6406  //                                                   true).
   6407 
   6408  // AsyncFromSyncIteratorContinuation is passed |closeOnRejection = true| iff
   6409  // completion-kind is not "return".
   6410  bool closeOnRejection = completionKind != CompletionKind::Return;
   6411 
   6412  // The step numbers below are for AsyncFromSyncIteratorContinuation().
   6413  //
   6414  // Step 1. NOTE: Because promiseCapability is derived from the intrinsic
   6415  //         %Promise%, the calls to promiseCapability.[[Reject]] entailed by
   6416  //         the use IfAbruptRejectPromise below are guaranteed not to throw.
   6417  // Step 2. Let done be Completion(IteratorComplete(result)).
   6418  // Step 3. IfAbruptRejectPromise(done, promiseCapability).
   6419  RootedValue doneVal(cx);
   6420  if (!GetProperty(cx, resultObj, resultObj, cx->names().done, &doneVal)) {
   6421    return AbruptRejectPromise(cx, args, resultPromise, nullptr);
   6422  }
   6423  bool done = ToBoolean(doneVal);
   6424 
   6425  // Step 4. Let value be Completion(IteratorValue(result)).
   6426  // Step 5. IfAbruptRejectPromise(value, promiseCapability).
   6427  RootedValue value(cx);
   6428  if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value)) {
   6429    return AbruptRejectPromise(cx, args, resultPromise, nullptr);
   6430  }
   6431 
   6432  // Step 9. Let unwrap be a new Abstract Closure with parameters (v) that
   6433  //         captures done and performs the following steps when called:
   6434  // Step 9.a. Return CreateIterResultObject(v, done).
   6435  // Step 10. Let onFulfilled be CreateBuiltinFunction(unwrap, 1, "", « »).
   6436  // Step 11. NOTE: onFulfilled is used when processing the "value" property
   6437  //          of an IteratorResult object in order to wait for its value if it
   6438  //          is a promise and re-package the result in a new "unwrapped"
   6439  //          IteratorResult object.
   6440  PromiseHandler onFulfilled =
   6441      done ? PromiseHandler::AsyncFromSyncIteratorValueUnwrapDone
   6442           : PromiseHandler::AsyncFromSyncIteratorValueUnwrapNotDone;
   6443 
   6444  // Step 12. If done is true, or if closeOnRejection is false, then
   6445  // Step 12.a. Let onRejected be undefined.
   6446  // Step 13. Else,
   6447  // Step 13.a. Let closeIterator be a new Abstract Closure with parameters
   6448  //            (error) that captures syncIteratorRecord and performs the
   6449  //            following steps when called:
   6450  // Step 13.a.i. Return ? IteratorClose(syncIteratorRecord,
   6451  //                                     ThrowCompletion(error)).
   6452  // Step 13.b. Let onRejected be CreateBuiltinFunction(closeIterator, 1, "",
   6453  //            «»).
   6454  // Step 13.c. NOTE: onRejected is used to close the Iterator when the "value"
   6455  //            property of an IteratorResult object it yields is a rejected
   6456  //            promise.
   6457  PromiseHandler onRejected = done || !closeOnRejection
   6458                                  ? PromiseHandler::Thrower
   6459                                  : PromiseHandler::AsyncFromSyncIteratorClose;
   6460 
   6461  // Steps 6, 8, and 14 are identical to some steps in Await; we have a utility
   6462  // function InternalAwait() that implements the idiom.
   6463  //
   6464  // Step 6. Let valueWrapper be Completion(PromiseResolve(%Promise%, value)).
   6465  // Step 8. IfAbruptRejectPromise(valueWrapper, promiseCapability).
   6466  // Step 14. Perform PerformPromiseThen(valueWrapper, onFulfilled,
   6467  //                                     onRejected, promiseCapability).
   6468  auto extra = [&](Handle<PromiseReactionRecord*> reaction) {
   6469    if (onRejected == PromiseHandler::AsyncFromSyncIteratorClose) {
   6470      reaction->setIsAsyncFromSyncIterator(asyncIter);
   6471    }
   6472  };
   6473  if (!InternalAwait(cx, value, resultPromise, onFulfilled, onRejected,
   6474                     extra)) {
   6475    // Reordering step 7 to this point is fine, because there are no other
   6476    // user-observable operations between steps 7-8 and 14. And |InternalAwait|,
   6477    // apart from the initial PromiseResolve, can only fail due to OOM. Since
   6478    // out-of-memory handling is not defined in the spec, we're also free
   6479    // reorder its effects. So w.r.t. spec-observable steps, calling
   6480    // |IteratorCloseForException| after |InternalAwait| has the same effect as
   6481    // performing IteratorClose directly after PromiseResolve.
   6482    //
   6483    // Step 7. If valueWrapper is an abrupt completion, done is false, and
   6484    //         closeOnRejection is true, then
   6485    // Step 7.a. Set valueWrapper to Completion(IteratorClose(
   6486    //           syncIteratorRecord, valueWrapper)).
   6487    //
   6488    // Check |cx->isExceptionPending()| because we don't want to perform
   6489    // IteratorClose for uncatchable exceptions. (IteratorCloseForException will
   6490    // also assert when there's no pending exception.)
   6491    if (cx->isExceptionPending() && !done && closeOnRejection) {
   6492      (void)IteratorCloseForException(cx, iter);
   6493    }
   6494    return AbruptRejectPromise(cx, args, resultPromise, nullptr);
   6495  }
   6496 
   6497  // Step 15. Return promiseCapability.[[Promise]].
   6498  args.rval().setObject(*resultPromise);
   6499  return true;
   6500 }
   6501 
   6502 /**
   6503 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   6504 *
   6505 * Promise.prototype.catch ( onRejected )
   6506 * https://tc39.es/ecma262/#sec-promise.prototype.catch
   6507 */
   6508 static bool Promise_catch_impl(JSContext* cx, unsigned argc, Value* vp,
   6509                               bool rvalExplicitlyUsed) {
   6510  CallArgs args = CallArgsFromVp(argc, vp);
   6511 
   6512  // Step 1. Let promise be the this value.
   6513  HandleValue thisVal = args.thisv();
   6514  HandleValue onFulfilled = UndefinedHandleValue;
   6515  HandleValue onRejected = args.get(0);
   6516 
   6517  // Fast path when the default Promise state is intact.
   6518  if (CanCallOriginalPromiseThenBuiltin(cx, thisVal)) {
   6519    return OriginalPromiseThenBuiltin(cx, thisVal, onFulfilled, onRejected,
   6520                                      args.rval(), rvalExplicitlyUsed);
   6521  }
   6522 
   6523  // Step 2. Return ? Invoke(promise, "then", « undefined, onRejected »).
   6524  RootedValue thenVal(cx);
   6525  RootedObject thisObj(cx, ToObject(cx, thisVal));
   6526  bool isOnProto = false;
   6527  bool isOnStandardProto = false;
   6528  bool isOnObjectProto = false;
   6529  if (!thisObj) {
   6530    return false;
   6531  }
   6532  if (!GetThenValue(cx, thisObj, thisVal, &thenVal, &isOnProto,
   6533                    &isOnStandardProto, &isOnObjectProto)) {
   6534    return false;
   6535  }
   6536 
   6537  if (IsNativeFunction(thenVal, &Promise_then) &&
   6538      thenVal.toObject().nonCCWRealm() == cx->realm()) {
   6539    return Promise_then_impl(cx, thisVal, onFulfilled, onRejected, args.rval(),
   6540                             rvalExplicitlyUsed);
   6541  }
   6542 
   6543  ReportThenable(cx, isOnProto, isOnStandardProto, isOnObjectProto);
   6544  return Call(cx, thenVal, thisVal, UndefinedHandleValue, onRejected,
   6545              args.rval());
   6546 }
   6547 
   6548 /**
   6549 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   6550 *
   6551 * Promise.prototype.catch ( onRejected )
   6552 * https://tc39.es/ecma262/#sec-promise.prototype.catch
   6553 */
   6554 static bool Promise_catch_noRetVal(JSContext* cx, unsigned argc, Value* vp) {
   6555  return Promise_catch_impl(cx, argc, vp, false);
   6556 }
   6557 
   6558 /**
   6559 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   6560 *
   6561 * Promise.prototype.catch ( onRejected )
   6562 * https://tc39.es/ecma262/#sec-promise.prototype.catch
   6563 */
   6564 static bool Promise_catch(JSContext* cx, unsigned argc, Value* vp) {
   6565  return Promise_catch_impl(cx, argc, vp, true);
   6566 }
   6567 
   6568 /**
   6569 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   6570 *
   6571 * Promise.prototype.then ( onFulfilled, onRejected )
   6572 * https://tc39.es/ecma262/#sec-promise.prototype.then
   6573 */
   6574 static bool Promise_then_impl(JSContext* cx, HandleValue promiseVal,
   6575                              HandleValue onFulfilled, HandleValue onRejected,
   6576                              MutableHandleValue rval,
   6577                              bool rvalExplicitlyUsed) {
   6578  // Step 1. Let promise be the this value.
   6579  // (implicit)
   6580 
   6581  // Step 2. If IsPromise(promise) is false, throw a TypeError exception.
   6582  if (!promiseVal.isObject()) {
   6583    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   6584                              JSMSG_OBJECT_REQUIRED,
   6585                              "Receiver of Promise.prototype.then call");
   6586    return false;
   6587  }
   6588 
   6589  // Fast path when the default Promise state is intact.
   6590  if (CanCallOriginalPromiseThenBuiltin(cx, promiseVal)) {
   6591    // Steps 3-5.
   6592    return OriginalPromiseThenBuiltin(cx, promiseVal, onFulfilled, onRejected,
   6593                                      rval, rvalExplicitlyUsed);
   6594  }
   6595 
   6596  RootedObject promiseObj(cx, &promiseVal.toObject());
   6597  Rooted<PromiseObject*> unwrappedPromise(
   6598      cx,
   6599      UnwrapAndTypeCheckValue<PromiseObject>(cx, promiseVal, [cx, &promiseVal] {
   6600        JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
   6601                                   JSMSG_INCOMPATIBLE_PROTO, "Promise", "then",
   6602                                   InformalValueTypeName(promiseVal));
   6603      }));
   6604  if (!unwrappedPromise) {
   6605    return false;
   6606  }
   6607 
   6608  bool rvalUsed =
   6609      rvalExplicitlyUsed ||
   6610      IsPromiseThenOrCatchRetValImplicitlyUsed(cx, unwrappedPromise);
   6611 
   6612  // Step 3. Let C be ? SpeciesConstructor(promise, %Promise%).
   6613  // Step 4. Let resultCapability be ? NewPromiseCapability(C).
   6614  CreateDependentPromise createDependent =
   6615      rvalUsed ? CreateDependentPromise::Always
   6616               : CreateDependentPromise::SkipIfCtorUnobservable;
   6617  Rooted<PromiseCapability> resultCapability(cx);
   6618  if (!PromiseThenNewPromiseCapability(cx, promiseObj, createDependent,
   6619                                       &resultCapability)) {
   6620    return false;
   6621  }
   6622 
   6623  // Step 5. Return PerformPromiseThen(promise, onFulfilled, onRejected,
   6624  //                                   resultCapability).
   6625  if (!PerformPromiseThen(cx, unwrappedPromise, onFulfilled, onRejected,
   6626                          resultCapability)) {
   6627    return false;
   6628  }
   6629 
   6630  if (rvalUsed) {
   6631    rval.setObject(*resultCapability.promise());
   6632  } else {
   6633    rval.setUndefined();
   6634  }
   6635  return true;
   6636 }
   6637 
   6638 /**
   6639 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   6640 *
   6641 * Promise.prototype.then ( onFulfilled, onRejected )
   6642 * https://tc39.es/ecma262/#sec-promise.prototype.then
   6643 */
   6644 bool Promise_then_noRetVal(JSContext* cx, unsigned argc, Value* vp) {
   6645  CallArgs args = CallArgsFromVp(argc, vp);
   6646  return Promise_then_impl(cx, args.thisv(), args.get(0), args.get(1),
   6647                           args.rval(), false);
   6648 }
   6649 
   6650 /**
   6651 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   6652 *
   6653 * Promise.prototype.then ( onFulfilled, onRejected )
   6654 * https://tc39.es/ecma262/#sec-promise.prototype.then
   6655 */
   6656 bool js::Promise_then(JSContext* cx, unsigned argc, Value* vp) {
   6657  CallArgs args = CallArgsFromVp(argc, vp);
   6658  return Promise_then_impl(cx, args.thisv(), args.get(0), args.get(1),
   6659                           args.rval(), true);
   6660 }
   6661 
   6662 /**
   6663 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   6664 *
   6665 * PerformPromiseThen ( promise, onFulfilled, onRejected
   6666 *                      [ , resultCapability ] )
   6667 * https://tc39.es/ecma262/#sec-performpromisethen
   6668 *
   6669 * Steps 1-12.
   6670 */
   6671 [[nodiscard]] static bool PerformPromiseThen(
   6672    JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled_,
   6673    HandleValue onRejected_, Handle<PromiseCapability> resultCapability) {
   6674  // Step 1. Assert: IsPromise(promise) is true.
   6675  // Step 2. If resultCapability is not present, then
   6676  // Step 2. a. Set resultCapability to undefined.
   6677  // (implicit)
   6678 
   6679  // (reordered)
   6680  // Step 4. Else,
   6681  // Step 4. a. Let onFulfilledJobCallback be HostMakeJobCallback(onFulfilled).
   6682  RootedValue onFulfilled(cx, onFulfilled_);
   6683 
   6684  // Step 3. If IsCallable(onFulfilled) is false, then
   6685  if (!IsCallable(onFulfilled)) {
   6686    // Step 3. a. Let onFulfilledJobCallback be empty.
   6687    onFulfilled = Int32Value(int32_t(PromiseHandler::Identity));
   6688  }
   6689 
   6690  // (reordered)
   6691  // Step 6. Else,
   6692  // Step 6. a. Let onRejectedJobCallback be HostMakeJobCallback(onRejected).
   6693  RootedValue onRejected(cx, onRejected_);
   6694 
   6695  // Step 5. If IsCallable(onRejected) is false, then
   6696  if (!IsCallable(onRejected)) {
   6697    // Step 5. a. Let onRejectedJobCallback be empty.
   6698    onRejected = Int32Value(int32_t(PromiseHandler::Thrower));
   6699  }
   6700 
   6701  // Step 7. Let fulfillReaction be the PromiseReaction
   6702  //         { [[Capability]]: resultCapability, [[Type]]: Fulfill,
   6703  //           [[Handler]]: onFulfilledJobCallback }.
   6704  // Step 8. Let rejectReaction be the PromiseReaction
   6705  //         { [[Capability]]: resultCapability, [[Type]]: Reject,
   6706  //           [[Handler]]: onRejectedJobCallback }.
   6707  //
   6708  // NOTE: We use single object for both reactions.
   6709  auto hostDefinedDataObjectOption =
   6710      promise->state() == JS::PromiseState::Pending
   6711          ? HostDefinedDataObjectOption::Allocate
   6712          : HostDefinedDataObjectOption::OptimizeOut;
   6713  Rooted<PromiseReactionRecord*> reaction(
   6714      cx, NewReactionRecord(cx, resultCapability, onFulfilled, onRejected,
   6715                            hostDefinedDataObjectOption));
   6716  if (!reaction) {
   6717    return false;
   6718  }
   6719 
   6720  // Steps 9-14.
   6721  return PerformPromiseThenWithReaction(cx, promise, reaction);
   6722 }
   6723 
   6724 /**
   6725 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   6726 *
   6727 * PerformPromiseThen ( promise, onFulfilled, onRejected
   6728 *                      [ , resultCapability ] )
   6729 * https://tc39.es/ecma262/#sec-performpromisethen
   6730 */
   6731 [[nodiscard]] static bool PerformPromiseThenWithoutSettleHandlers(
   6732    JSContext* cx, Handle<PromiseObject*> promise,
   6733    Handle<PromiseObject*> promiseToResolve,
   6734    Handle<PromiseCapability> resultCapability) {
   6735  // Step 1. Assert: IsPromise(promise) is true.
   6736  // Step 2. If resultCapability is not present, then
   6737  // (implicit)
   6738 
   6739  // Step 3. If IsCallable(onFulfilled) is false, then
   6740  // Step 3.a. Let onFulfilledJobCallback be empty.
   6741  HandleValue onFulfilled = NullHandleValue;
   6742 
   6743  // Step 5. If IsCallable(onRejected) is false, then
   6744  // Step 5.a. Let onRejectedJobCallback be empty.
   6745  HandleValue onRejected = NullHandleValue;
   6746 
   6747  // When the promise's state isn't pending, the embedding
   6748  // should be able to retrieve the host defined object
   6749  // on their own, so here we optimize out from the
   6750  // our side.
   6751  auto hostDefinedDataObjectOption =
   6752      promise->state() == JS::PromiseState::Pending
   6753          ? HostDefinedDataObjectOption::Allocate
   6754          : HostDefinedDataObjectOption::OptimizeOut;
   6755 
   6756  // Step 7. Let fulfillReaction be the PromiseReaction
   6757  //         { [[Capability]]: resultCapability, [[Type]]: Fulfill,
   6758  //           [[Handler]]: onFulfilledJobCallback }.
   6759  // Step 8. Let rejectReaction be the PromiseReaction
   6760  //         { [[Capability]]: resultCapability, [[Type]]: Reject,
   6761  //           [[Handler]]: onRejectedJobCallback }.
   6762  Rooted<PromiseReactionRecord*> reaction(
   6763      cx, NewReactionRecord(cx, resultCapability, onFulfilled, onRejected,
   6764                            hostDefinedDataObjectOption));
   6765  if (!reaction) {
   6766    return false;
   6767  }
   6768 
   6769  reaction->setIsDefaultResolvingHandler(promiseToResolve);
   6770 
   6771  // Steps 9-12.
   6772  return PerformPromiseThenWithReaction(cx, promise, reaction);
   6773 }
   6774 
   6775 /**
   6776 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   6777 *
   6778 * PerformPromiseThen ( promise, onFulfilled, onRejected
   6779 *                      [ , resultCapability ] )
   6780 * https://tc39.github.io/ecma262/#sec-performpromisethen
   6781 *
   6782 * Steps 9-12.
   6783 */
   6784 [[nodiscard]] static bool PerformPromiseThenWithReaction(
   6785    JSContext* cx, Handle<PromiseObject*> unwrappedPromise,
   6786    Handle<PromiseReactionRecord*> reaction) {
   6787  // Step 9. If promise.[[PromiseState]] is pending, then
   6788  JS::PromiseState state = unwrappedPromise->state();
   6789  int32_t flags = unwrappedPromise->flags();
   6790  if (state == JS::PromiseState::Pending) {
   6791    // Step 9.a. Append fulfillReaction as the last element of the List that is
   6792    //           promise.[[PromiseFulfillReactions]].
   6793    // Step 9.b. Append rejectReaction as the last element of the List that is
   6794    //           promise.[[PromiseRejectReactions]].
   6795    //
   6796    // Instead of creating separate reaction records for fulfillment and
   6797    // rejection, we create a combined record. All places we use the record
   6798    // can handle that.
   6799    if (!AddPromiseReaction(cx, unwrappedPromise, reaction)) {
   6800      return false;
   6801    }
   6802  }
   6803 
   6804  // Steps 10-11.
   6805  else {
   6806    // Step 11.a. Assert: The value of promise.[[PromiseState]] is rejected.
   6807    MOZ_ASSERT_IF(state != JS::PromiseState::Fulfilled,
   6808                  state == JS::PromiseState::Rejected);
   6809 
   6810    // Step 10.a. Let value be promise.[[PromiseResult]].
   6811    // Step 11.b. Let reason be promise.[[PromiseResult]].
   6812    RootedValue valueOrReason(cx, unwrappedPromise->valueOrReason());
   6813 
   6814    // We might be operating on a promise from another compartment. In that
   6815    // case, we need to wrap the result/reason value before using it.
   6816    if (!cx->compartment()->wrap(cx, &valueOrReason)) {
   6817      return false;
   6818    }
   6819 
   6820    // Step 11.c. If promise.[[PromiseIsHandled]] is false,
   6821    //            perform HostPromiseRejectionTracker(promise, "handle").
   6822    if (state == JS::PromiseState::Rejected &&
   6823        !(flags & PROMISE_FLAG_HANDLED)) {
   6824      cx->runtime()->removeUnhandledRejectedPromise(cx, unwrappedPromise);
   6825    }
   6826 
   6827    // Step 10.b. Let fulfillJob be
   6828    //            NewPromiseReactionJob(fulfillReaction, value).
   6829    // Step 10.c. Perform HostEnqueuePromiseJob(fulfillJob.[[Job]],
   6830    //                                          fulfillJob.[[Realm]]).
   6831    // Step 11.d. Let rejectJob be
   6832    //            NewPromiseReactionJob(rejectReaction, reason).
   6833    // Step 11.e. Perform HostEnqueuePromiseJob(rejectJob.[[Job]],
   6834    //                                          rejectJob.[[Realm]]).
   6835    if (!EnqueuePromiseReactionJob(cx, reaction, valueOrReason, state)) {
   6836      return false;
   6837    }
   6838  }
   6839 
   6840  // Step 12. Set promise.[[PromiseIsHandled]] to true.
   6841  unwrappedPromise->setHandled();
   6842 
   6843  return true;
   6844 }
   6845 
   6846 /**
   6847 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   6848 *
   6849 * PerformPromiseThen ( promise, onFulfilled, onRejected
   6850 *                      [ , resultCapability ] )
   6851 * https://tc39.github.io/ecma262/#sec-performpromisethen
   6852 *
   6853 * Steps 9.a-b.
   6854 */
   6855 [[nodiscard]] static bool AddPromiseReaction(
   6856    JSContext* cx, Handle<PromiseObject*> unwrappedPromise,
   6857    Handle<PromiseReactionRecord*> reaction) {
   6858  MOZ_RELEASE_ASSERT(reaction->is<PromiseReactionRecord>());
   6859  RootedValue reactionVal(cx, ObjectValue(*reaction));
   6860 
   6861  // The code that creates Promise reactions can handle wrapped Promises,
   6862  // unwrapping them as needed. That means that the `promise` and `reaction`
   6863  // objects we have here aren't necessarily from the same compartment. In
   6864  // order to store the reaction on the promise, we have to ensure that it
   6865  // is properly wrapped.
   6866  mozilla::Maybe<AutoRealm> ar;
   6867  if (unwrappedPromise->compartment() != cx->compartment()) {
   6868    ar.emplace(cx, unwrappedPromise);
   6869    if (!cx->compartment()->wrap(cx, &reactionVal)) {
   6870      return false;
   6871    }
   6872  }
   6873  Handle<PromiseObject*> promise = unwrappedPromise;
   6874 
   6875  // Step 9.a. Append fulfillReaction as the last element of the List that is
   6876  //           promise.[[PromiseFulfillReactions]].
   6877  // Step 9.b. Append rejectReaction as the last element of the List that is
   6878  //           promise.[[PromiseRejectReactions]].
   6879  RootedValue reactionsVal(cx, promise->reactions());
   6880 
   6881  if (reactionsVal.isUndefined()) {
   6882    // If no reactions existed so far, just store the reaction record directly.
   6883    promise->setFixedSlot(PromiseSlot_ReactionsOrResult, reactionVal);
   6884    return true;
   6885  }
   6886 
   6887  RootedObject reactionsObj(cx, &reactionsVal.toObject());
   6888 
   6889  // If only a single reaction exists, it's stored directly instead of in a
   6890  // list. In that case, `reactionsObj` might be a wrapper, which we can
   6891  // always safely unwrap.
   6892  if (IsProxy(reactionsObj)) {
   6893    reactionsObj = UncheckedUnwrap(reactionsObj);
   6894    if (JS_IsDeadWrapper(reactionsObj)) {
   6895      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   6896                                JSMSG_DEAD_OBJECT);
   6897      return false;
   6898    }
   6899    MOZ_RELEASE_ASSERT(reactionsObj->is<PromiseReactionRecord>());
   6900  }
   6901 
   6902  if (reactionsObj->is<PromiseReactionRecord>()) {
   6903    // If a single reaction existed so far, create a list and store the
   6904    // old and the new reaction in it.
   6905    ArrayObject* reactions = NewDenseFullyAllocatedArray(cx, 2);
   6906    if (!reactions) {
   6907      return false;
   6908    }
   6909 
   6910    reactions->setDenseInitializedLength(2);
   6911    reactions->initDenseElement(0, reactionsVal);
   6912    reactions->initDenseElement(1, reactionVal);
   6913 
   6914    promise->setFixedSlot(PromiseSlot_ReactionsOrResult,
   6915                          ObjectValue(*reactions));
   6916  } else {
   6917    // Otherwise, just store the new reaction.
   6918    MOZ_RELEASE_ASSERT(reactionsObj->is<NativeObject>());
   6919    Handle<NativeObject*> reactions = reactionsObj.as<NativeObject>();
   6920    uint32_t len = reactions->getDenseInitializedLength();
   6921    DenseElementResult result = reactions->ensureDenseElements(cx, len, 1);
   6922    if (result != DenseElementResult::Success) {
   6923      MOZ_ASSERT(result == DenseElementResult::Failure);
   6924      return false;
   6925    }
   6926    reactions->setDenseElement(len, reactionVal);
   6927  }
   6928 
   6929  return true;
   6930 }
   6931 
   6932 [[nodiscard]] static bool AddDummyPromiseReactionForDebugger(
   6933    JSContext* cx, Handle<PromiseObject*> promise,
   6934    HandleObject dependentPromise) {
   6935  if (promise->state() != JS::PromiseState::Pending) {
   6936    return true;
   6937  }
   6938 
   6939  if (JS_IsDeadWrapper(UncheckedUnwrap(dependentPromise))) {
   6940    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
   6941    return false;
   6942  }
   6943 
   6944  // `dependentPromise` should be a maybe-wrapped Promise.
   6945  MOZ_ASSERT(UncheckedUnwrap(dependentPromise)->is<PromiseObject>());
   6946 
   6947  // Leave resolve and reject as null.
   6948  Rooted<PromiseCapability> capability(cx);
   6949  capability.promise().set(dependentPromise);
   6950 
   6951  Rooted<PromiseReactionRecord*> reaction(
   6952      cx, NewReactionRecord(cx, capability, NullHandleValue, NullHandleValue,
   6953                            HostDefinedDataObjectOption::UnusedForDebugger));
   6954  if (!reaction) {
   6955    return false;
   6956  }
   6957 
   6958  reaction->setIsDebuggerDummy();
   6959 
   6960  return AddPromiseReaction(cx, promise, reaction);
   6961 }
   6962 
   6963 uint64_t PromiseObject::getID() { return PromiseDebugInfo::id(this); }
   6964 
   6965 double PromiseObject::lifetime() {
   6966  return MillisecondsSinceStartup() - allocationTime();
   6967 }
   6968 
   6969 /**
   6970 * Returns all promises that directly depend on this one. That means those
   6971 * created by calling `then` on this promise, or the promise returned by
   6972 * `Promise.all(iterable)` or `Promise.race(iterable)`, with this promise
   6973 * being a member of the passed-in `iterable`.
   6974 *
   6975 * Per spec, we should have separate lists of reaction records for the
   6976 * fulfill and reject cases. As an optimization, we have only one of those,
   6977 * containing the required data for both cases. So we just walk that list
   6978 * and extract the dependent promises from all reaction records.
   6979 */
   6980 bool PromiseObject::dependentPromises(JSContext* cx,
   6981                                      MutableHandle<GCVector<Value>> values) {
   6982  if (state() != JS::PromiseState::Pending) {
   6983    return true;
   6984  }
   6985 
   6986  uint32_t valuesIndex = 0;
   6987  RootedValue reactionsVal(cx, reactions());
   6988 
   6989  return ForEachReaction(cx, reactionsVal, [&](MutableHandleObject obj) {
   6990    if (IsProxy(obj)) {
   6991      obj.set(UncheckedUnwrap(obj));
   6992    }
   6993 
   6994    if (JS_IsDeadWrapper(obj)) {
   6995      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   6996                                JSMSG_DEAD_OBJECT);
   6997      return false;
   6998    }
   6999 
   7000    MOZ_RELEASE_ASSERT(obj->is<PromiseReactionRecord>());
   7001    auto* reaction = &obj->as<PromiseReactionRecord>();
   7002 
   7003    // Not all reactions have a Promise on them.
   7004    JSObject* promiseObj = reaction->promise();
   7005    if (promiseObj) {
   7006      if (!values.growBy(1)) {
   7007        return false;
   7008      }
   7009 
   7010      values[valuesIndex++].setObject(*promiseObj);
   7011    }
   7012    return true;
   7013  });
   7014 }
   7015 
   7016 bool PromiseObject::forEachReactionRecord(
   7017    JSContext* cx, PromiseReactionRecordBuilder& builder) {
   7018  if (state() != JS::PromiseState::Pending) {
   7019    // Promise was resolved, so no reaction records are present.
   7020    return true;
   7021  }
   7022 
   7023  RootedValue reactionsVal(cx, reactions());
   7024  if (reactionsVal.isNullOrUndefined()) {
   7025    // No reaction records are attached to this promise.
   7026    return true;
   7027  }
   7028 
   7029  return ForEachReaction(cx, reactionsVal, [&](MutableHandleObject obj) {
   7030    if (IsProxy(obj)) {
   7031      obj.set(UncheckedUnwrap(obj));
   7032    }
   7033 
   7034    if (JS_IsDeadWrapper(obj)) {
   7035      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   7036                                JSMSG_DEAD_OBJECT);
   7037      return false;
   7038    }
   7039 
   7040    Rooted<PromiseReactionRecord*> reaction(cx,
   7041                                            &obj->as<PromiseReactionRecord>());
   7042    MOZ_ASSERT(reaction->targetState() == JS::PromiseState::Pending);
   7043 
   7044    if (reaction->isAsyncFunction()) {
   7045      Rooted<AsyncFunctionGeneratorObject*> generator(
   7046          cx, reaction->asyncFunctionGenerator());
   7047      if (!builder.asyncFunction(cx, generator)) {
   7048        return false;
   7049      }
   7050    } else if (reaction->isAsyncGenerator()) {
   7051      Rooted<AsyncGeneratorObject*> generator(cx, reaction->asyncGenerator());
   7052      if (!builder.asyncGenerator(cx, generator)) {
   7053        return false;
   7054      }
   7055    } else if (reaction->isDefaultResolvingHandler()) {
   7056      Rooted<PromiseObject*> promise(cx, reaction->defaultResolvingPromise());
   7057      if (!builder.direct(cx, promise)) {
   7058        return false;
   7059      }
   7060    } else {
   7061      RootedObject resolve(cx);
   7062      RootedObject reject(cx);
   7063      RootedObject result(cx, reaction->promise());
   7064 
   7065      Value v = reaction->getFixedSlot(PromiseReactionRecord::OnFulfilled);
   7066      if (v.isObject()) {
   7067        resolve = &v.toObject();
   7068      }
   7069 
   7070      v = reaction->getFixedSlot(PromiseReactionRecord::OnRejected);
   7071      if (v.isObject()) {
   7072        reject = &v.toObject();
   7073      }
   7074 
   7075      if (!builder.then(cx, resolve, reject, result)) {
   7076        return false;
   7077      }
   7078    }
   7079 
   7080    return true;
   7081  });
   7082 }
   7083 
   7084 /**
   7085 * ES2023 draft rev 714fa3dd1e8237ae9c666146270f81880089eca5
   7086 *
   7087 * Promise Reject Functions
   7088 * https://tc39.es/ecma262/#sec-promise-reject-functions
   7089 */
   7090 static bool CallDefaultPromiseResolveFunction(JSContext* cx,
   7091                                              Handle<PromiseObject*> promise,
   7092                                              HandleValue resolutionValue) {
   7093  MOZ_ASSERT(IsPromiseWithDefaultResolvingFunction(promise));
   7094 
   7095  // Steps 1-3.
   7096  // (implicit)
   7097 
   7098  // Step 4. Let alreadyResolved be F.[[AlreadyResolved]].
   7099  // Step 5. If alreadyResolved.[[Value]] is true, return undefined.
   7100  if (IsAlreadyResolvedPromiseWithDefaultResolvingFunction(promise)) {
   7101    return true;
   7102  }
   7103 
   7104  // Step 6. Set alreadyResolved.[[Value]] to true.
   7105  SetAlreadyResolvedPromiseWithDefaultResolvingFunction(promise);
   7106 
   7107  // Steps 7-15.
   7108  // (implicit) Step 16. Return undefined.
   7109  return ResolvePromiseInternal(cx, promise, resolutionValue);
   7110 }
   7111 
   7112 /* static */
   7113 bool PromiseObject::resolve(JSContext* cx, Handle<PromiseObject*> promise,
   7114                            HandleValue resolutionValue) {
   7115  MOZ_ASSERT(!PromiseHasAnyFlag(*promise, PROMISE_FLAG_ASYNC));
   7116  if (promise->state() != JS::PromiseState::Pending) {
   7117    return true;
   7118  }
   7119 
   7120  if (IsPromiseWithDefaultResolvingFunction(promise)) {
   7121    return CallDefaultPromiseResolveFunction(cx, promise, resolutionValue);
   7122  }
   7123 
   7124  JSFunction* resolveFun = GetResolveFunctionFromPromise(promise);
   7125  if (!resolveFun) {
   7126    return true;
   7127  }
   7128 
   7129  RootedValue funVal(cx, ObjectValue(*resolveFun));
   7130 
   7131  // For xray'd Promises, the resolve fun may have been created in another
   7132  // compartment. For the call below to work in that case, wrap the
   7133  // function into the current compartment.
   7134  if (!cx->compartment()->wrap(cx, &funVal)) {
   7135    return false;
   7136  }
   7137 
   7138  RootedValue dummy(cx);
   7139  return Call(cx, funVal, UndefinedHandleValue, resolutionValue, &dummy);
   7140 }
   7141 
   7142 /**
   7143 * ES2023 draft rev 714fa3dd1e8237ae9c666146270f81880089eca5
   7144 *
   7145 * Promise Reject Functions
   7146 * https://tc39.es/ecma262/#sec-promise-reject-functions
   7147 */
   7148 static bool CallDefaultPromiseRejectFunction(
   7149    JSContext* cx, Handle<PromiseObject*> promise, HandleValue rejectionValue,
   7150    JS::Handle<SavedFrame*> unwrappedRejectionStack /* = nullptr */) {
   7151  MOZ_ASSERT(IsPromiseWithDefaultResolvingFunction(promise));
   7152 
   7153  // Steps 1-3.
   7154  // (implicit)
   7155 
   7156  // Step 4. Let alreadyResolved be F.[[AlreadyResolved]].
   7157  // Step 5. If alreadyResolved.[[Value]] is true, return undefined.
   7158  if (IsAlreadyResolvedPromiseWithDefaultResolvingFunction(promise)) {
   7159    return true;
   7160  }
   7161 
   7162  // Step 6. Set alreadyResolved.[[Value]] to true.
   7163  SetAlreadyResolvedPromiseWithDefaultResolvingFunction(promise);
   7164 
   7165  return RejectPromiseInternal(cx, promise, rejectionValue,
   7166                               unwrappedRejectionStack);
   7167 }
   7168 
   7169 /* static */
   7170 bool PromiseObject::reject(JSContext* cx, Handle<PromiseObject*> promise,
   7171                           HandleValue rejectionValue) {
   7172  MOZ_ASSERT(!PromiseHasAnyFlag(*promise, PROMISE_FLAG_ASYNC));
   7173  if (promise->state() != JS::PromiseState::Pending) {
   7174    return true;
   7175  }
   7176 
   7177  if (IsPromiseWithDefaultResolvingFunction(promise)) {
   7178    return CallDefaultPromiseRejectFunction(cx, promise, rejectionValue);
   7179  }
   7180 
   7181  RootedValue funVal(cx, promise->getFixedSlot(PromiseSlot_RejectFunction));
   7182  MOZ_ASSERT(IsCallable(funVal));
   7183 
   7184  RootedValue dummy(cx);
   7185  return Call(cx, funVal, UndefinedHandleValue, rejectionValue, &dummy);
   7186 }
   7187 
   7188 /**
   7189 * ES2022 draft rev d03c1ec6e235a5180fa772b6178727c17974cb14
   7190 *
   7191 * RejectPromise ( promise, reason )
   7192 * https://tc39.es/ecma262/#sec-rejectpromise
   7193 *
   7194 * Step 7.
   7195 */
   7196 /* static */
   7197 void PromiseObject::onSettled(JSContext* cx, Handle<PromiseObject*> promise,
   7198                              Handle<SavedFrame*> unwrappedRejectionStack) {
   7199  PromiseDebugInfo::setResolutionInfo(cx, promise, unwrappedRejectionStack);
   7200 
   7201  // Step 7. If promise.[[PromiseIsHandled]] is false, perform
   7202  //         HostPromiseRejectionTracker(promise, "reject").
   7203  if (promise->state() == JS::PromiseState::Rejected &&
   7204      promise->isUnhandled()) {
   7205    cx->runtime()->addUnhandledRejectedPromise(cx, promise);
   7206  }
   7207 
   7208  DebugAPI::onPromiseSettled(cx, promise);
   7209 }
   7210 
   7211 void PromiseObject::setRequiresUserInteractionHandling(bool state) {
   7212  if (state) {
   7213    AddPromiseFlags(*this, PROMISE_FLAG_REQUIRES_USER_INTERACTION_HANDLING);
   7214  } else {
   7215    RemovePromiseFlags(*this, PROMISE_FLAG_REQUIRES_USER_INTERACTION_HANDLING);
   7216  }
   7217 }
   7218 
   7219 void PromiseObject::setHadUserInteractionUponCreation(bool state) {
   7220  if (state) {
   7221    AddPromiseFlags(*this, PROMISE_FLAG_HAD_USER_INTERACTION_UPON_CREATION);
   7222  } else {
   7223    RemovePromiseFlags(*this, PROMISE_FLAG_HAD_USER_INTERACTION_UPON_CREATION);
   7224  }
   7225 }
   7226 
   7227 void PromiseObject::copyUserInteractionFlagsFrom(PromiseObject& rhs) {
   7228  setRequiresUserInteractionHandling(rhs.requiresUserInteractionHandling());
   7229  setHadUserInteractionUponCreation(rhs.hadUserInteractionUponCreation());
   7230 }
   7231 
   7232 #if defined(DEBUG) || defined(JS_JITSPEW)
   7233 void PromiseDebugInfo::dumpOwnFields(js::JSONPrinter& json) const {
   7234  if (getFixedSlot(Slot_Id).isNumber()) {
   7235    json.formatProperty("id", "%lf", getFixedSlot(Slot_Id).toNumber());
   7236  }
   7237 
   7238  if (getFixedSlot(Slot_AllocationTime).isNumber()) {
   7239    json.formatProperty("allocationTime", "%lf",
   7240                        getFixedSlot(Slot_AllocationTime).toNumber());
   7241  }
   7242 
   7243  {
   7244    js::GenericPrinter& out = json.beginStringProperty("allocationSite");
   7245    getFixedSlot(Slot_AllocationSite).dumpStringContent(out);
   7246    json.endStringProperty();
   7247  }
   7248 
   7249  if (getFixedSlot(Slot_ResolutionTime).isNumber()) {
   7250    json.formatProperty("resolutionTime", "%lf",
   7251                        getFixedSlot(Slot_ResolutionTime).toNumber());
   7252  }
   7253 
   7254  {
   7255    js::GenericPrinter& out = json.beginStringProperty("resolutionSite");
   7256    getFixedSlot(Slot_ResolutionSite).dumpStringContent(out);
   7257    json.endStringProperty();
   7258  }
   7259 }
   7260 
   7261 template <typename KnownF, typename UnknownF>
   7262 /* static */
   7263 void PromiseReactionRecord::forEachReactionFlag(uint32_t flags, KnownF known,
   7264                                                UnknownF unknown) {
   7265  for (uint32_t i = 1; i; i = i << 1) {
   7266    if (!(flags & i)) {
   7267      continue;
   7268    }
   7269    switch (flags & i) {
   7270      case REACTION_FLAG_RESOLVED:
   7271        known("RESOLVED");
   7272        break;
   7273      case REACTION_FLAG_FULFILLED:
   7274        known("FULFILLED");
   7275        break;
   7276      case REACTION_FLAG_DEFAULT_RESOLVING_HANDLER:
   7277        known("DEFAULT_RESOLVING_HANDLER");
   7278        break;
   7279      case REACTION_FLAG_ASYNC_FUNCTION:
   7280        known("ASYNC_FUNCTION");
   7281        break;
   7282      case REACTION_FLAG_ASYNC_GENERATOR:
   7283        known("ASYNC_GENERATOR");
   7284        break;
   7285      case REACTION_FLAG_DEBUGGER_DUMMY:
   7286        known("DEBUGGER_DUMMY");
   7287        break;
   7288      case REACTION_FLAG_IGNORE_UNHANDLED_REJECTION:
   7289        known("IGNORE_UNHANDLED_REJECTION");
   7290        break;
   7291      default:
   7292        unknown(i);
   7293        break;
   7294    }
   7295  }
   7296 }
   7297 
   7298 void PromiseReactionRecord::dumpOwnFields(js::JSONPrinter& json) const {
   7299  if (promise()) {
   7300    js::GenericPrinter& out = json.beginStringProperty("promise");
   7301    promise()->dumpStringContent(out);
   7302    json.endStringProperty();
   7303  }
   7304 
   7305  if (targetState() == JS::PromiseState::Fulfilled) {
   7306    {
   7307      js::GenericPrinter& out = json.beginStringProperty("onFulfilled");
   7308      getFixedSlot(OnFulfilled).dumpStringContent(out);
   7309      json.endStringProperty();
   7310    }
   7311    {
   7312      js::GenericPrinter& out = json.beginStringProperty("onFulfilledArg");
   7313      getFixedSlot(OnFulfilledArg).dumpStringContent(out);
   7314      json.endStringProperty();
   7315    }
   7316  }
   7317 
   7318  if (targetState() == JS::PromiseState::Rejected) {
   7319    {
   7320      js::GenericPrinter& out = json.beginStringProperty("onRejected");
   7321      getFixedSlot(OnRejected).dumpStringContent(out);
   7322      json.endStringProperty();
   7323    }
   7324    {
   7325      js::GenericPrinter& out = json.beginStringProperty("onRejectedArg");
   7326      getFixedSlot(OnRejectedArg).dumpStringContent(out);
   7327      json.endStringProperty();
   7328    }
   7329  }
   7330 
   7331  if (!getFixedSlot(Resolve).isNull()) {
   7332    js::GenericPrinter& out = json.beginStringProperty("resolve");
   7333    getFixedSlot(Resolve).dumpStringContent(out);
   7334    json.endStringProperty();
   7335  }
   7336 
   7337  if (!getFixedSlot(Reject).isNull()) {
   7338    js::GenericPrinter& out = json.beginStringProperty("reject");
   7339    getFixedSlot(Reject).dumpStringContent(out);
   7340    json.endStringProperty();
   7341  }
   7342 
   7343  {
   7344    js::GenericPrinter& out = json.beginStringProperty("hostDefinedData");
   7345    getFixedSlot(HostDefinedData).dumpStringContent(out);
   7346    json.endStringProperty();
   7347  }
   7348 
   7349  json.beginInlineListProperty("flags");
   7350  forEachReactionFlag(
   7351      flags(), [&](const char* name) { json.value("%s", name); },
   7352      [&](uint32_t value) { json.value("Unknown(%08x)", value); });
   7353  json.endInlineList();
   7354 
   7355  if (isDefaultResolvingHandler()) {
   7356    js::GenericPrinter& out = json.beginStringProperty("promiseToResolve");
   7357    getFixedSlot(GeneratorOrPromiseToResolveOrAsyncFromSyncIterator)
   7358        .dumpStringContent(out);
   7359    json.endStringProperty();
   7360  }
   7361 
   7362  if (isAsyncFunction()) {
   7363    js::GenericPrinter& out = json.beginStringProperty("generator");
   7364    getFixedSlot(GeneratorOrPromiseToResolveOrAsyncFromSyncIterator)
   7365        .dumpStringContent(out);
   7366    json.endStringProperty();
   7367  }
   7368 
   7369  if (isAsyncGenerator()) {
   7370    js::GenericPrinter& out = json.beginStringProperty("generator");
   7371    getFixedSlot(GeneratorOrPromiseToResolveOrAsyncFromSyncIterator)
   7372        .dumpStringContent(out);
   7373    json.endStringProperty();
   7374  }
   7375 }
   7376 
   7377 void DumpReactions(js::JSONPrinter& json, const JS::Value& reactionsVal) {
   7378  if (reactionsVal.isUndefined()) {
   7379    return;
   7380  }
   7381 
   7382  if (reactionsVal.isObject()) {
   7383    JSObject* reactionsObj = &reactionsVal.toObject();
   7384    if (IsProxy(reactionsObj)) {
   7385      reactionsObj = UncheckedUnwrap(reactionsObj);
   7386    }
   7387 
   7388    if (reactionsObj->is<PromiseReactionRecord>()) {
   7389      json.beginObject();
   7390      reactionsObj->as<PromiseReactionRecord>().dumpOwnFields(json);
   7391      json.endObject();
   7392      return;
   7393    }
   7394 
   7395    if (reactionsObj->is<NativeObject>()) {
   7396      NativeObject* reactionsList = &reactionsObj->as<NativeObject>();
   7397      uint32_t len = reactionsList->getDenseInitializedLength();
   7398      for (uint32_t i = 0; i < len; i++) {
   7399        const JS::Value& reactionVal = reactionsList->getDenseElement(i);
   7400        if (reactionVal.isObject()) {
   7401          JSObject* reactionsObj = &reactionVal.toObject();
   7402          if (IsProxy(reactionsObj)) {
   7403            reactionsObj = UncheckedUnwrap(reactionsObj);
   7404          }
   7405 
   7406          if (reactionsObj->is<PromiseReactionRecord>()) {
   7407            json.beginObject();
   7408            reactionsObj->as<PromiseReactionRecord>().dumpOwnFields(json);
   7409            json.endObject();
   7410            continue;
   7411          }
   7412        }
   7413 
   7414        js::GenericPrinter& out = json.beginString();
   7415        out.put("Unknown(");
   7416        reactionVal.dumpStringContent(out);
   7417        out.put(")");
   7418        json.endString();
   7419      }
   7420      return;
   7421    }
   7422  }
   7423 
   7424  js::GenericPrinter& out = json.beginString();
   7425  out.put("Unknown(");
   7426  reactionsVal.dumpStringContent(out);
   7427  out.put(")");
   7428  json.endString();
   7429 }
   7430 
   7431 template <typename KnownF, typename UnknownF>
   7432 void ForEachPromiseFlag(uint32_t flags, KnownF known, UnknownF unknown) {
   7433  for (uint32_t i = 1; i; i = i << 1) {
   7434    if (!(flags & i)) {
   7435      continue;
   7436    }
   7437    switch (flags & i) {
   7438      case PROMISE_FLAG_RESOLVED:
   7439        known("RESOLVED");
   7440        break;
   7441      case PROMISE_FLAG_FULFILLED:
   7442        known("FULFILLED");
   7443        break;
   7444      case PROMISE_FLAG_HANDLED:
   7445        known("HANDLED");
   7446        break;
   7447      case PROMISE_FLAG_DEFAULT_RESOLVING_FUNCTIONS:
   7448        known("DEFAULT_RESOLVING_FUNCTIONS");
   7449        break;
   7450      case PROMISE_FLAG_DEFAULT_RESOLVING_FUNCTIONS_ALREADY_RESOLVED:
   7451        known("DEFAULT_RESOLVING_FUNCTIONS_ALREADY_RESOLVED");
   7452        break;
   7453      case PROMISE_FLAG_ASYNC:
   7454        known("ASYNC");
   7455        break;
   7456      case PROMISE_FLAG_REQUIRES_USER_INTERACTION_HANDLING:
   7457        known("REQUIRES_USER_INTERACTION_HANDLING");
   7458        break;
   7459      case PROMISE_FLAG_HAD_USER_INTERACTION_UPON_CREATION:
   7460        known("HAD_USER_INTERACTION_UPON_CREATION");
   7461        break;
   7462      default:
   7463        unknown(i);
   7464        break;
   7465    }
   7466  }
   7467 }
   7468 
   7469 void PromiseObject::dumpOwnFields(js::JSONPrinter& json) const {
   7470  json.beginInlineListProperty("flags");
   7471  ForEachPromiseFlag(
   7472      flags(), [&](const char* name) { json.value("%s", name); },
   7473      [&](uint32_t value) { json.value("Unknown(%08x)", value); });
   7474  json.endInlineList();
   7475 
   7476  if (state() == JS::PromiseState::Pending) {
   7477    json.property("state", "pending");
   7478 
   7479    json.beginListProperty("reactions");
   7480    DumpReactions(json, reactions());
   7481    json.endList();
   7482  } else if (state() == JS::PromiseState::Fulfilled) {
   7483    json.property("state", "fulfilled");
   7484 
   7485    json.beginObjectProperty("value");
   7486    value().dumpFields(json);
   7487    json.endObject();
   7488  } else if (state() == JS::PromiseState::Rejected) {
   7489    json.property("state", "rejected");
   7490 
   7491    json.beginObjectProperty("reason");
   7492    reason().dumpFields(json);
   7493    json.endObject();
   7494  }
   7495 
   7496  JS::Value debugInfo = getFixedSlot(PromiseSlot_DebugInfo);
   7497  if (debugInfo.isNumber()) {
   7498    json.formatProperty("id", "%lf", debugInfo.toNumber());
   7499  } else if (debugInfo.isObject() &&
   7500             debugInfo.toObject().is<PromiseDebugInfo>()) {
   7501    debugInfo.toObject().as<PromiseDebugInfo>().dumpOwnFields(json);
   7502  }
   7503 }
   7504 
   7505 void PromiseObject::dumpOwnStringContent(js::GenericPrinter& out) const {}
   7506 #endif
   7507 
   7508 // We can skip `await` with an already resolved value only if the current frame
   7509 // is the topmost JS frame and the current job is the last job in the job queue.
   7510 // This guarantees that any new job enqueued in the current turn will be
   7511 // executed immediately after the current job.
   7512 //
   7513 // Currently we only support skipping jobs when the async function is resumed
   7514 // at least once.
   7515 [[nodiscard]] static bool IsTopMostAsyncFunctionCall(JSContext* cx) {
   7516  FrameIter iter(cx);
   7517 
   7518  // The current frame should be the async function.
   7519  if (iter.done()) {
   7520    return false;
   7521  }
   7522 
   7523  if (!iter.isFunctionFrame() && iter.isModuleFrame()) {
   7524    // The iterator is not a function frame, it is a module frame.
   7525    // Ignore this optimization for now.
   7526    return true;
   7527  }
   7528 
   7529  MOZ_ASSERT(iter.calleeTemplate()->isAsync());
   7530 
   7531 #ifdef DEBUG
   7532  bool isGenerator = iter.calleeTemplate()->isGenerator();
   7533 #endif
   7534 
   7535  ++iter;
   7536 
   7537  // The parent frame should be the `next` function of the generator that is
   7538  // internally called in AsyncFunctionResume resp. AsyncGeneratorResume.
   7539  if (iter.done()) {
   7540    return false;
   7541  }
   7542  // The initial call into an async function can happen from top-level code, so
   7543  // the parent frame isn't required to be a function frame. Contrary to that,
   7544  // the parent frame for an async generator function is always a function
   7545  // frame, because async generators can't directly fall through to an `await`
   7546  // expression from their initial call.
   7547  if (!iter.isFunctionFrame()) {
   7548    MOZ_ASSERT(!isGenerator);
   7549    return false;
   7550  }
   7551 
   7552  // Always skip InterpretGeneratorResume if present.
   7553  JSFunction* fun = iter.calleeTemplate();
   7554  if (IsSelfHostedFunctionWithName(fun, cx->names().InterpretGeneratorResume)) {
   7555    ++iter;
   7556 
   7557    if (iter.done()) {
   7558      return false;
   7559    }
   7560 
   7561    MOZ_ASSERT(iter.isFunctionFrame());
   7562    fun = iter.calleeTemplate();
   7563  }
   7564 
   7565  if (!IsSelfHostedFunctionWithName(fun, cx->names().AsyncFunctionNext) &&
   7566      !IsSelfHostedFunctionWithName(fun, cx->names().AsyncGeneratorNext)) {
   7567    return false;
   7568  }
   7569 
   7570  ++iter;
   7571 
   7572  // There should be no more frames.
   7573  if (iter.done()) {
   7574    return true;
   7575  }
   7576 
   7577  return false;
   7578 }
   7579 
   7580 [[nodiscard]] bool js::CanSkipAwait(JSContext* cx, HandleValue val,
   7581                                    bool* canSkip) {
   7582  if (!cx->canSkipEnqueuingJobs) {
   7583    *canSkip = false;
   7584    return true;
   7585  }
   7586 
   7587  if (!IsTopMostAsyncFunctionCall(cx)) {
   7588    *canSkip = false;
   7589    return true;
   7590  }
   7591 
   7592  // Primitive values cannot be 'thenables', so we can trivially skip the
   7593  // await operation.
   7594  if (!val.isObject()) {
   7595    *canSkip = true;
   7596    return true;
   7597  }
   7598 
   7599  JSObject* obj = &val.toObject();
   7600  if (!obj->is<PromiseObject>()) {
   7601    *canSkip = false;
   7602    return true;
   7603  }
   7604 
   7605  PromiseObject* promise = &obj->as<PromiseObject>();
   7606 
   7607  if (promise->state() == JS::PromiseState::Pending) {
   7608    *canSkip = false;
   7609    return true;
   7610  }
   7611 
   7612  if (!IsPromiseWithDefaultProperties(promise, cx)) {
   7613    *canSkip = false;
   7614    return true;
   7615  }
   7616 
   7617  if (promise->state() == JS::PromiseState::Rejected) {
   7618    // We don't optimize rejected Promises for now.
   7619    *canSkip = false;
   7620    return true;
   7621  }
   7622 
   7623  *canSkip = true;
   7624  return true;
   7625 }
   7626 
   7627 [[nodiscard]] bool js::ExtractAwaitValue(JSContext* cx, HandleValue val,
   7628                                         MutableHandleValue resolved) {
   7629 // Ensure all callers of this are jumping past the
   7630 // extract if it's not possible to extract.
   7631 #ifdef DEBUG
   7632  bool canSkip;
   7633  if (!CanSkipAwait(cx, val, &canSkip)) {
   7634    return false;
   7635  }
   7636  MOZ_ASSERT(canSkip == true);
   7637 #endif
   7638 
   7639  // Primitive values cannot be 'thenables', so we can trivially skip the
   7640  // await operation.
   7641  if (!val.isObject()) {
   7642    resolved.set(val);
   7643    return true;
   7644  }
   7645 
   7646  JSObject* obj = &val.toObject();
   7647  PromiseObject* promise = &obj->as<PromiseObject>();
   7648  resolved.set(promise->value());
   7649 
   7650  return true;
   7651 }
   7652 
   7653 JS_PUBLIC_API bool JS::RunJSMicroTask(JSContext* cx,
   7654                                      Handle<JS::JSMicroTask*> entry) {
   7655 #ifdef DEBUG
   7656  JSObject* global = JS::GetExecutionGlobalFromJSMicroTask(entry);
   7657  MOZ_ASSERT_IF(global, global == cx->global());
   7658 #endif
   7659 
   7660  RootedObject task(cx, entry);
   7661  RootedObject unwrappedTask(cx, UncheckedUnwrap(entry));
   7662  if (JS_IsDeadWrapper(unwrappedTask)) {
   7663    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
   7664    return false;
   7665  }
   7666 
   7667  if (unwrappedTask->is<PromiseReactionRecord>()) {
   7668    // Note: We don't store a callback for promise reaction records because they
   7669    // always call back into PromiseReactionJob.
   7670    //
   7671    // Note: We pass the (maybe)wrapped task here since PromiseReactionJob will
   7672    // decide what realm to be in based on the wrapper if it exists.
   7673    return PromiseReactionJob(cx, task);
   7674  }
   7675 
   7676  if (unwrappedTask->is<ThenableJob>()) {
   7677    ThenableJob* job = &unwrappedTask->as<ThenableJob>();
   7678    ThenableJob::TargetFunction target = job->targetFunction();
   7679 
   7680    // MG:XXX: Note: Because we don't care about the result of these values
   7681    // after the call, do these really have to be rooted (I don't think so?)
   7682    RootedTuple<JSObject*, Value, JSObject*, JSObject*> roots(cx);
   7683    RootedField<JSObject*, 0> promise(roots, job->promise());
   7684    RootedField<Value, 1> thenable(roots, job->thenable());
   7685 
   7686    switch (target) {
   7687      case ThenableJob::PromiseResolveThenableJob: {
   7688        // MG:XXX: Unify naming: is it `then` or `handler` make up your mind.
   7689        RootedField<JSObject*, 3> then(roots, job->then());
   7690        return PromiseResolveThenableJob(cx, promise, thenable, then);
   7691      }
   7692      case ThenableJob::PromiseResolveBuiltinThenableJob: {
   7693        RootedField<JSObject*, 2> thenableObj(roots,
   7694                                              &job->thenable().toObject());
   7695        return PromiseResolveBuiltinThenableJob(cx, promise, thenableObj);
   7696      }
   7697    }
   7698    MOZ_CRASH("Corrupted Target Function");
   7699    return false;
   7700  }
   7701 
   7702  MOZ_CRASH("Unknown Job type");
   7703  return false;
   7704 }
   7705 
   7706 template <>
   7707 inline bool JSObject::is<MicroTaskEntry>() const {
   7708  return is<ThenableJob>() || is<PromiseReactionRecord>();
   7709 }
   7710 
   7711 JS_PUBLIC_API bool JS::MaybeGetHostDefinedDataFromJSMicroTask(
   7712    JS::JSMicroTask* entry, MutableHandleObject out) {
   7713  out.set(nullptr);
   7714  JSObject* task = CheckedUnwrapStatic(entry);
   7715  if (!task) {
   7716    return false;
   7717  }
   7718  if (JS_IsDeadWrapper(task)) {
   7719    return false;
   7720  }
   7721 
   7722  MOZ_ASSERT(task->is<MicroTaskEntry>());
   7723  JSObject* maybeHostDefined =
   7724      task->as<MicroTaskEntry>().getHostDefinedData().toObjectOrNull();
   7725 
   7726  if (!maybeHostDefined) {
   7727    return true;
   7728  }
   7729 
   7730  if (JS_IsDeadWrapper(maybeHostDefined)) {
   7731    return false;
   7732  }
   7733 
   7734  JSObject* unwrapped = CheckedUnwrapStatic(maybeHostDefined);
   7735  if (!unwrapped) {
   7736    return false;
   7737  }
   7738  out.set(unwrapped);
   7739  return true;
   7740 }
   7741 
   7742 JS_PUBLIC_API bool JS::MaybeGetAllocationSiteFromJSMicroTask(
   7743    JS::JSMicroTask* entry, MutableHandleObject out) {
   7744  JSObject* task = UncheckedUnwrap(entry);
   7745  if (JS_IsDeadWrapper(task)) {
   7746    return false;
   7747  };
   7748 
   7749  MOZ_ASSERT(task->is<MicroTaskEntry>());
   7750  JSObject* maybeWrappedStack = task->as<MicroTaskEntry>().allocationStack();
   7751 
   7752  if (!maybeWrappedStack) {
   7753    out.set(nullptr);
   7754    return true;
   7755  }
   7756 
   7757  if (JS_IsDeadWrapper(maybeWrappedStack)) {
   7758    return false;
   7759  }
   7760 
   7761  JSObject* unwrapped = UncheckedUnwrap(maybeWrappedStack);
   7762  MOZ_ASSERT(unwrapped->is<SavedFrame>());
   7763  out.set(unwrapped);
   7764  return true;
   7765 }
   7766 
   7767 JS_PUBLIC_API JSObject* JS::MaybeGetHostDefinedGlobalFromJSMicroTask(
   7768    JSMicroTask* entry) {
   7769  JSObject* task = UncheckedUnwrap(entry);
   7770  if (JS_IsDeadWrapper(task)) {
   7771    return nullptr;
   7772  }
   7773 
   7774  MOZ_ASSERT(task->is<MicroTaskEntry>());
   7775 
   7776  JSObject* maybeWrappedHostDefinedRepresentative =
   7777      task->as<MicroTaskEntry>().hostDefinedGlobalRepresentative();
   7778 
   7779  if (maybeWrappedHostDefinedRepresentative) {
   7780    JSObject* unwrapped =
   7781        UncheckedUnwrap(maybeWrappedHostDefinedRepresentative);
   7782    if (JS_IsDeadWrapper(unwrapped)) {
   7783      return nullptr;
   7784    }
   7785    return &unwrapped->nonCCWGlobal();
   7786  }
   7787 
   7788  return nullptr;
   7789 }
   7790 
   7791 JS_PUBLIC_API JSObject* JS::GetExecutionGlobalFromJSMicroTask(
   7792    JS::JSMicroTask* entry) {
   7793  JSObject* unwrapped = UncheckedUnwrap(entry);
   7794  if (JS_IsDeadWrapper(unwrapped)) {
   7795    return nullptr;
   7796  }
   7797 
   7798  if (unwrapped->is<PromiseReactionRecord>()) {
   7799    // Use the stored equeue representative (which may need to be unwrapped)
   7800    JSObject* enqueueGlobalRepresentative =
   7801        unwrapped->as<PromiseReactionRecord>().enqueueGlobalRepresentative();
   7802    JSObject* unwrappedRepresentative =
   7803        UncheckedUnwrap(enqueueGlobalRepresentative);
   7804 
   7805    if (JS_IsDeadWrapper(unwrappedRepresentative)) {
   7806      return nullptr;
   7807    }
   7808 
   7809    return &unwrappedRepresentative->nonCCWGlobal();
   7810  }
   7811 
   7812  // Thenable jobs are allocated in the right realm+global and so we
   7813  // can just use nonCCWGlobal;
   7814  if (unwrapped->is<ThenableJob>()) {
   7815    return &unwrapped->nonCCWGlobal();
   7816  }
   7817 
   7818  MOZ_CRASH("Somehow we lost the execution global");
   7819 }
   7820 
   7821 JS_PUBLIC_API JSObject* JS::MaybeGetPromiseFromJSMicroTask(
   7822    JS::JSMicroTask* entry) {
   7823  JSObject* unwrapped = UncheckedUnwrap(entry);
   7824  if (JS_IsDeadWrapper(unwrapped)) {
   7825    return nullptr;
   7826  }
   7827 
   7828  if (unwrapped->is<MicroTaskEntry>()) {
   7829    return unwrapped->as<MicroTaskEntry>().promise();
   7830  }
   7831  return nullptr;
   7832 }
   7833 
   7834 JS_PUBLIC_API bool JS::GetFlowIdFromJSMicroTask(JS::JSMicroTask* entry,
   7835                                                uint64_t* uid) {
   7836  // We want to make sure we get the flow id from the target object
   7837  // not the wrapper.
   7838  JSObject* unwrapped = UncheckedUnwrap(entry);
   7839  if (JS_IsDeadWrapper(unwrapped)) {
   7840    return false;
   7841  }
   7842 
   7843  MOZ_ASSERT(unwrapped->is<MicroTaskEntry>(), "Only use on JSMicroTasks");
   7844 
   7845  *uid = js::gc::GetUniqueIdInfallible(unwrapped);
   7846  return true;
   7847 }
   7848 
   7849 JS_PUBLIC_API JS::JSMicroTask* JS::ToUnwrappedJSMicroTask(
   7850    const JS::GenericMicroTask& genericMicroTask) {
   7851  if (!genericMicroTask.isObject()) {
   7852    return nullptr;
   7853  }
   7854 
   7855  JSObject* unwrapped = UncheckedUnwrap(&genericMicroTask.toObject());
   7856 
   7857  // On the off chance someone hands us a dead wrapper.
   7858  if (JS_IsDeadWrapper(unwrapped)) {
   7859    return nullptr;
   7860  }
   7861  if (!unwrapped->is<MicroTaskEntry>()) {
   7862    return nullptr;
   7863  }
   7864 
   7865  return unwrapped;
   7866 }
   7867 
   7868 JS_PUBLIC_API JS::JSMicroTask* JS::ToMaybeWrappedJSMicroTask(
   7869    const JS::GenericMicroTask& genericMicroTask) {
   7870  if (!genericMicroTask.isObject()) {
   7871    return nullptr;
   7872  }
   7873 
   7874  return &genericMicroTask.toObject();
   7875 }
   7876 
   7877 JS_PUBLIC_API bool JS::IsJSMicroTask(const JS::GenericMicroTask& hv) {
   7878  return JS::ToUnwrappedJSMicroTask(hv) != nullptr;
   7879 }
   7880 
   7881 JS::AutoDebuggerJobQueueInterruption::AutoDebuggerJobQueueInterruption()
   7882    : cx(nullptr) {}
   7883 
   7884 JS::AutoDebuggerJobQueueInterruption::~AutoDebuggerJobQueueInterruption() {
   7885  MOZ_ASSERT_IF(initialized() && !cx->jobQueue->isDrainingStopped(),
   7886                cx->jobQueue->empty());
   7887 }
   7888 
   7889 bool JS::AutoDebuggerJobQueueInterruption::init(JSContext* cx) {
   7890  MOZ_ASSERT(cx->jobQueue);
   7891  this->cx = cx;
   7892  saved = cx->jobQueue->saveJobQueue(cx);
   7893  return !!saved;
   7894 }
   7895 
   7896 void JS::AutoDebuggerJobQueueInterruption::runJobs() {
   7897  JS::AutoSaveExceptionState ases(cx);
   7898  cx->jobQueue->runJobs(cx);
   7899 }
   7900 
   7901 const JSJitInfo promise_then_info = {
   7902    {(JSJitGetterOp)Promise_then_noRetVal},
   7903    {0}, /* unused */
   7904    {0}, /* unused */
   7905    JSJitInfo::IgnoresReturnValueNative,
   7906    JSJitInfo::AliasEverything,
   7907    JSVAL_TYPE_UNDEFINED,
   7908 };
   7909 
   7910 const JSJitInfo promise_catch_info = {
   7911    {(JSJitGetterOp)Promise_catch_noRetVal},
   7912    {0}, /* unused */
   7913    {0}, /* unused */
   7914    JSJitInfo::IgnoresReturnValueNative,
   7915    JSJitInfo::AliasEverything,
   7916    JSVAL_TYPE_UNDEFINED,
   7917 };
   7918 
   7919 static const JSFunctionSpec promise_methods[] = {
   7920    JS_FNINFO("then", js::Promise_then, &promise_then_info, 2, 0),
   7921    JS_FNINFO("catch", Promise_catch, &promise_catch_info, 1, 0),
   7922    JS_SELF_HOSTED_FN("finally", "Promise_finally", 1, 0),
   7923    JS_FS_END,
   7924 };
   7925 
   7926 static const JSPropertySpec promise_properties[] = {
   7927    JS_STRING_SYM_PS(toStringTag, "Promise", JSPROP_READONLY),
   7928    JS_PS_END,
   7929 };
   7930 
   7931 static const JSFunctionSpec promise_static_methods[] = {
   7932    JS_FN("all", Promise_static_all, 1, 0),
   7933    JS_FN("allSettled", Promise_static_allSettled, 1, 0),
   7934 #ifdef NIGHTLY_BUILD
   7935    JS_FN("allKeyed", Promise_static_allKeyed, 1, 0),
   7936    JS_FN("allSettledKeyed", Promise_static_allSettledKeyed, 1, 0),
   7937 #endif
   7938    JS_FN("any", Promise_static_any, 1, 0),
   7939    JS_FN("race", Promise_static_race, 1, 0),
   7940    JS_FN("reject", Promise_reject, 1, 0),
   7941    JS_FN("resolve", js::Promise_static_resolve, 1, 0),
   7942    JS_FN("withResolvers", Promise_static_withResolvers, 0, 0),
   7943    JS_FN("try", Promise_static_try, 1, 0),
   7944    JS_FS_END,
   7945 };
   7946 
   7947 static const JSPropertySpec promise_static_properties[] = {
   7948    JS_SYM_GET(species, js::Promise_static_species, 0),
   7949    JS_PS_END,
   7950 };
   7951 
   7952 static const ClassSpec PromiseObjectClassSpec = {
   7953    GenericCreateConstructor<PromiseConstructor, 1, gc::AllocKind::FUNCTION>,
   7954    GenericCreatePrototype<PromiseObject>,
   7955    promise_static_methods,
   7956    promise_static_properties,
   7957    promise_methods,
   7958    promise_properties,
   7959    GenericFinishInit<WhichHasRealmFuseProperty::ProtoAndCtor>,
   7960 };
   7961 
   7962 const JSClass PromiseObject::class_ = {
   7963    "Promise",
   7964    JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
   7965        JSCLASS_HAS_CACHED_PROTO(JSProto_Promise) |
   7966        JSCLASS_HAS_XRAYED_CONSTRUCTOR,
   7967    JS_NULL_CLASS_OPS,
   7968    &PromiseObjectClassSpec,
   7969 };
   7970 
   7971 const JSClass PromiseObject::protoClass_ = {
   7972    "Promise.prototype",
   7973    JSCLASS_HAS_CACHED_PROTO(JSProto_Promise),
   7974    JS_NULL_CLASS_OPS,
   7975    &PromiseObjectClassSpec,
   7976 };