tor-browser

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

AsyncIteration.cpp (64551B)


      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 "vm/AsyncIteration.h"
      8 
      9 #include "builtin/Promise.h"  // js::PromiseHandler, js::CreatePromiseObjectForAsyncGenerator, js::AsyncFromSyncIteratorMethod, js::ResolvePromiseInternal, js::RejectPromiseInternal, js::InternalAsyncGeneratorAwait
     10 #include "js/friend/ErrorMessages.h"  // js::GetErrorMessage, JSMSG_*
     11 #include "js/PropertySpec.h"
     12 #include "vm/CompletionKind.h"
     13 #include "vm/FunctionFlags.h"  // js::FunctionFlags
     14 #include "vm/GeneratorObject.h"
     15 #include "vm/GlobalObject.h"
     16 #include "vm/Interpreter.h"
     17 #include "vm/PlainObject.h"    // js::PlainObject
     18 #include "vm/PromiseObject.h"  // js::PromiseObject
     19 #include "vm/Realm.h"
     20 #include "vm/SelfHosting.h"
     21 
     22 #include "vm/JSObject-inl.h"
     23 #include "vm/List-inl.h"
     24 
     25 using namespace js;
     26 
     27 // ---------------
     28 // Async generator
     29 // ---------------
     30 
     31 const JSClass AsyncGeneratorObject::class_ = {
     32    "AsyncGenerator",
     33    JSCLASS_HAS_RESERVED_SLOTS(AsyncGeneratorObject::Slots),
     34    &classOps_,
     35 };
     36 
     37 const JSClassOps AsyncGeneratorObject::classOps_ = {
     38    nullptr,                                   // addProperty
     39    nullptr,                                   // delProperty
     40    nullptr,                                   // enumerate
     41    nullptr,                                   // newEnumerate
     42    nullptr,                                   // resolve
     43    nullptr,                                   // mayResolve
     44    nullptr,                                   // finalize
     45    nullptr,                                   // call
     46    nullptr,                                   // construct
     47    CallTraceMethod<AbstractGeneratorObject>,  // trace
     48 };
     49 
     50 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
     51 //
     52 // OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto
     53 //                                 [ , internalSlotsList ] )
     54 // https://tc39.es/ecma262/#sec-ordinarycreatefromconstructor
     55 //
     56 // specialized for AsyncGeneratorObjects.
     57 static AsyncGeneratorObject* OrdinaryCreateFromConstructorAsynGen(
     58    JSContext* cx, HandleFunction constructor) {
     59  // Step 1. Assert: intrinsicDefaultProto is this specification's name of an
     60  //         intrinsic object. The corresponding object must be an intrinsic
     61  //         that is intended to be used as the [[Prototype]] value of an
     62  //         object.
     63  // (implicit)
     64 
     65  // Step 2. Let proto be
     66  //         ? GetPrototypeFromConstructor(constructor, intrinsicDefaultProto).
     67  RootedValue protoVal(cx);
     68  if (!GetProperty(cx, constructor, constructor, cx->names().prototype,
     69                   &protoVal)) {
     70    return nullptr;
     71  }
     72 
     73  RootedObject proto(cx, protoVal.isObject() ? &protoVal.toObject() : nullptr);
     74  if (!proto) {
     75    proto = GlobalObject::getOrCreateAsyncGeneratorPrototype(cx, cx->global());
     76    if (!proto) {
     77      return nullptr;
     78    }
     79  }
     80 
     81  // Step 3. If internalSlotsList is present, let slotsList be
     82  //         internalSlotsList.
     83  // Step 4. Else, let slotsList be a new empty List.
     84  // Step 5. Return OrdinaryObjectCreate(proto, slotsList).
     85  return NewObjectWithGivenProto<AsyncGeneratorObject>(cx, proto);
     86 }
     87 
     88 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
     89 //
     90 // EvaluateAsyncGeneratorBody
     91 // https://tc39.es/ecma262/#sec-runtime-semantics-evaluateasyncgeneratorbody
     92 //
     93 // Steps 4-5.
     94 //
     95 // AsyncGeneratorStart ( generator, generatorBody )
     96 // https://tc39.es/ecma262/#sec-asyncgeneratorstart
     97 //
     98 // Steps 1, 7.
     99 /* static */
    100 AsyncGeneratorObject* AsyncGeneratorObject::create(JSContext* cx,
    101                                                   HandleFunction asyncGen) {
    102  MOZ_ASSERT(asyncGen->isAsync() && asyncGen->isGenerator());
    103 
    104  AsyncGeneratorObject* generator =
    105      OrdinaryCreateFromConstructorAsynGen(cx, asyncGen);
    106  if (!generator) {
    107    return nullptr;
    108  }
    109 
    110  // EvaluateAsyncGeneratorBody
    111  // Step 4. Set generator.[[AsyncGeneratorState]] to suspended-start.
    112  generator->setSuspendedStart();
    113 
    114  // Step 5. Perform AsyncGeneratorStart(generator, FunctionBody).
    115 
    116  // AsyncGeneratorStart
    117  // Step 1. Assert: generator.[[AsyncGeneratorState]] is suspended-start.
    118 
    119  // Step 7. Set generator.[[AsyncGeneratorQueue]] to a new empty List.
    120  generator->clearSingleQueueRequest();
    121 
    122  generator->clearCachedRequest();
    123 
    124  return generator;
    125 }
    126 
    127 /* static */
    128 AsyncGeneratorRequest* AsyncGeneratorObject::createRequest(
    129    JSContext* cx, Handle<AsyncGeneratorObject*> generator,
    130    CompletionKind completionKind, HandleValue completionValue,
    131    Handle<PromiseObject*> promise) {
    132  if (!generator->hasCachedRequest()) {
    133    return AsyncGeneratorRequest::create(cx, completionKind, completionValue,
    134                                         promise);
    135  }
    136 
    137  AsyncGeneratorRequest* request = generator->takeCachedRequest();
    138  request->init(completionKind, completionValue, promise);
    139  return request;
    140 }
    141 
    142 /* static */ [[nodiscard]] bool AsyncGeneratorObject::enqueueRequest(
    143    JSContext* cx, Handle<AsyncGeneratorObject*> generator,
    144    Handle<AsyncGeneratorRequest*> request) {
    145  if (generator->isSingleQueue()) {
    146    if (generator->isSingleQueueEmpty()) {
    147      generator->setSingleQueueRequest(request);
    148      return true;
    149    }
    150 
    151    ListObject* queue = ListObject::create(cx);
    152    if (!queue) {
    153      return false;
    154    }
    155 
    156    if (!queue->append(cx, ObjectValue(*generator->singleQueueRequest()))) {
    157      return false;
    158    }
    159    if (!queue->append(cx, ObjectValue(*request))) {
    160      return false;
    161    }
    162 
    163    generator->setQueue(queue);
    164    return true;
    165  }
    166 
    167  return generator->queue()->append(cx, ObjectValue(*request));
    168 }
    169 
    170 /* static */
    171 AsyncGeneratorRequest* AsyncGeneratorObject::dequeueRequest(
    172    JSContext* cx, Handle<AsyncGeneratorObject*> generator) {
    173  if (generator->isSingleQueue()) {
    174    AsyncGeneratorRequest* request = generator->singleQueueRequest();
    175    generator->clearSingleQueueRequest();
    176    return request;
    177  }
    178 
    179  Rooted<ListObject*> queue(cx, generator->queue());
    180  return &queue->popFirstAs<AsyncGeneratorRequest>(cx);
    181 }
    182 
    183 /* static */
    184 AsyncGeneratorRequest* AsyncGeneratorObject::peekRequest(
    185    Handle<AsyncGeneratorObject*> generator) {
    186  if (generator->isSingleQueue()) {
    187    return generator->singleQueueRequest();
    188  }
    189 
    190  return &generator->queue()->getAs<AsyncGeneratorRequest>(0);
    191 }
    192 
    193 const JSClass AsyncGeneratorRequest::class_ = {
    194    "AsyncGeneratorRequest",
    195    JSCLASS_HAS_RESERVED_SLOTS(AsyncGeneratorRequest::Slots),
    196 };
    197 
    198 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
    199 //
    200 // AsyncGeneratorRequest Records
    201 // https://tc39.es/ecma262/#sec-asyncgeneratorrequest-records
    202 /* static */
    203 AsyncGeneratorRequest* AsyncGeneratorRequest::create(
    204    JSContext* cx, CompletionKind completionKind, HandleValue completionValue,
    205    Handle<PromiseObject*> promise) {
    206  AsyncGeneratorRequest* request =
    207      NewObjectWithGivenProto<AsyncGeneratorRequest>(cx, nullptr);
    208  if (!request) {
    209    return nullptr;
    210  }
    211 
    212  request->init(completionKind, completionValue, promise);
    213  return request;
    214 }
    215 
    216 [[nodiscard]] static bool AsyncGeneratorResume(
    217    JSContext* cx, Handle<AsyncGeneratorObject*> generator,
    218    CompletionKind completionKind, HandleValue argument);
    219 
    220 [[nodiscard]] static bool AsyncGeneratorDrainQueue(
    221    JSContext* cx, Handle<AsyncGeneratorObject*> generator);
    222 
    223 [[nodiscard]] static bool AsyncGeneratorCompleteStepNormal(
    224    JSContext* cx, Handle<AsyncGeneratorObject*> generator, HandleValue value,
    225    bool done);
    226 
    227 [[nodiscard]] static bool AsyncGeneratorCompleteStepThrow(
    228    JSContext* cx, Handle<AsyncGeneratorObject*> generator,
    229    HandleValue exception);
    230 
    231 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
    232 //
    233 // AsyncGeneratorStart ( generator, generatorBody )
    234 // https://tc39.es/ecma262/#sec-asyncgeneratorstart
    235 //
    236 // Steps 4.g-l. "return" case.
    237 [[nodiscard]] static bool AsyncGeneratorReturned(
    238    JSContext* cx, Handle<AsyncGeneratorObject*> generator, HandleValue value) {
    239  // Step 4.g. Set acGenerator.[[AsyncGeneratorState]] to draining-queue.
    240  generator->setDrainingQueue();
    241 
    242  // Step 4.i. If result is a return completion, set result to
    243  //           NormalCompletion(result.[[Value]]).
    244  // (implicit)
    245 
    246  // Step 4.j. Perform AsyncGeneratorCompleteStep(acGenerator, result, true).
    247  if (!AsyncGeneratorCompleteStepNormal(cx, generator, value, true)) {
    248    return false;
    249  }
    250 
    251  MOZ_ASSERT(!generator->isExecuting());
    252  MOZ_ASSERT(!generator->isExecuting_AwaitingYieldReturn());
    253  if (generator->isDrainingQueue_AwaitingReturn()) {
    254    return true;
    255  }
    256 
    257  // Step 4.k. Perform AsyncGeneratorDrainQueue(acGenerator).
    258  // Step 4.l. Return undefined.
    259  return AsyncGeneratorDrainQueue(cx, generator);
    260 }
    261 
    262 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
    263 //
    264 // AsyncGeneratorStart ( generator, generatorBody )
    265 // https://tc39.es/ecma262/#sec-asyncgeneratorstart
    266 //
    267 // Steps 4.g-l. "throw" case.
    268 [[nodiscard]] static bool AsyncGeneratorThrown(
    269    JSContext* cx, Handle<AsyncGeneratorObject*> generator) {
    270  // Step 4.g. Set acGenerator.[[AsyncGeneratorState]] to draining-queue.
    271  generator->setDrainingQueue();
    272 
    273  // Not much we can do about uncatchable exceptions, so just bail.
    274  if (!cx->isExceptionPending()) {
    275    return false;
    276  }
    277 
    278  // Step 4.j. Perform AsyncGeneratorCompleteStep(acGenerator, result, true).
    279  RootedValue value(cx);
    280  if (!GetAndClearException(cx, &value)) {
    281    return false;
    282  }
    283  if (!AsyncGeneratorCompleteStepThrow(cx, generator, value)) {
    284    return false;
    285  }
    286 
    287  MOZ_ASSERT(!generator->isExecuting());
    288  MOZ_ASSERT(!generator->isExecuting_AwaitingYieldReturn());
    289  if (generator->isDrainingQueue_AwaitingReturn()) {
    290    return true;
    291  }
    292 
    293  // Step 4.k. Perform AsyncGeneratorDrainQueue(acGenerator).
    294  // Step 4.l. Return undefined.
    295  return AsyncGeneratorDrainQueue(cx, generator);
    296 }
    297 
    298 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
    299 //
    300 // AsyncGeneratorUnwrapYieldResumption ( resumptionValue )
    301 // https://tc39.es/ecma262/#sec-asyncgeneratorunwrapyieldresumption
    302 //
    303 // Steps 4-5.
    304 [[nodiscard]] static bool AsyncGeneratorYieldReturnAwaitedFulfilled(
    305    JSContext* cx, Handle<AsyncGeneratorObject*> generator, HandleValue value) {
    306  MOZ_ASSERT(generator->isExecuting_AwaitingYieldReturn(),
    307             "YieldReturn-Await fulfilled when not in "
    308             "'AwaitingYieldReturn' state");
    309 
    310  // Step 4. Assert: awaited is a normal completion.
    311  // Step 5. Return ReturnCompletion(awaited.[[Value]]).
    312  return AsyncGeneratorResume(cx, generator, CompletionKind::Return, value);
    313 }
    314 
    315 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
    316 //
    317 // AsyncGeneratorUnwrapYieldResumption ( resumptionValue )
    318 // https://tc39.es/ecma262/#sec-asyncgeneratorunwrapyieldresumption
    319 //
    320 // Step 3.
    321 [[nodiscard]] static bool AsyncGeneratorYieldReturnAwaitedRejected(
    322    JSContext* cx, Handle<AsyncGeneratorObject*> generator,
    323    HandleValue reason) {
    324  MOZ_ASSERT(
    325      generator->isExecuting_AwaitingYieldReturn(),
    326      "YieldReturn-Await rejected when not in 'AwaitingYieldReturn' state");
    327 
    328  // Step 3. If awaited is a throw completion, return ? awaited.
    329  return AsyncGeneratorResume(cx, generator, CompletionKind::Throw, reason);
    330 }
    331 
    332 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
    333 //
    334 // AsyncGeneratorUnwrapYieldResumption ( resumptionValue )
    335 // https://tc39.es/ecma262/#sec-asyncgeneratorunwrapyieldresumption
    336 //
    337 // Step 2.
    338 [[nodiscard]] static bool AsyncGeneratorUnwrapYieldResumptionWithReturn(
    339    JSContext* cx, Handle<AsyncGeneratorObject*> generator,
    340    JS::Handle<JS::Value> value) {
    341  // Step 2. Let awaited be Completion(Await(resumptionValue.[[Value]])).
    342  //
    343  // NOTE: Given that Await needs to be performed asynchronously,
    344  //       we use an implementation-defined state "AwaitingYieldReturn"
    345  //       to wait for the result.
    346  generator->setExecuting_AwaitingYieldReturn();
    347 
    348  return InternalAsyncGeneratorAwait(
    349      cx, generator, value,
    350      PromiseHandler::AsyncGeneratorYieldReturnAwaitedFulfilled,
    351      PromiseHandler::AsyncGeneratorYieldReturnAwaitedRejected);
    352 }
    353 
    354 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
    355 //
    356 // AsyncGeneratorYield ( value )
    357 // https://tc39.es/ecma262/#sec-asyncgeneratoryield
    358 //
    359 // Stesp 9-12.
    360 //
    361 // AsyncGeneratorUnwrapYieldResumption ( resumptionValue )
    362 // https://tc39.es/ecma262/#sec-asyncgeneratorunwrapyieldresumption
    363 //
    364 // Step 1.
    365 [[nodiscard]] static bool AsyncGeneratorYield(
    366    JSContext* cx, Handle<AsyncGeneratorObject*> generator, HandleValue value,
    367    bool* resumeAgain, CompletionKind* resumeCompletionKind,
    368    JS::MutableHandle<JS::Value> resumeValue) {
    369  *resumeAgain = false;
    370 
    371  // Step 9. Perform
    372  //         ! AsyncGeneratorCompleteStep(generator, completion, false,
    373  //                                      previousRealm).
    374  if (!AsyncGeneratorCompleteStepNormal(cx, generator, value, false)) {
    375    return false;
    376  }
    377 
    378  MOZ_ASSERT(!generator->isExecuting_AwaitingYieldReturn());
    379  // NOTE: This transition doesn't basically happen, but could happen if
    380  //       Debugger API is used, or the job queue is forcibly drained.
    381  if (generator->isDrainingQueue_AwaitingReturn()) {
    382    return true;
    383  }
    384 
    385  // Step 10. Let queue be generator.[[AsyncGeneratorQueue]].
    386  // Step 11. If queue is not empty, then
    387  if (!generator->isQueueEmpty()) {
    388    // Step 11.a. NOTE: Execution continues without suspending the generator.
    389    // Step 11.b. Let toYield be the first element of queue.
    390    Rooted<AsyncGeneratorRequest*> toYield(
    391        cx, AsyncGeneratorObject::peekRequest(generator));
    392    if (!toYield) {
    393      return false;
    394    }
    395 
    396    CompletionKind completionKind = toYield->completionKind();
    397 
    398    // Step 11.c. Let resumptionValue be Completion(toYield.[[Completion]]).
    399    RootedValue completionValue(cx, toYield->completionValue());
    400 
    401    // Step 11.d. Return ?
    402    //            AsyncGeneratorUnwrapYieldResumption(resumptionValue).
    403    //
    404    // AsyncGeneratorUnwrapYieldResumption
    405    // Step 1. If resumptionValue is not a return completion, return ?
    406    //         resumptionValue.
    407    if (completionKind != CompletionKind::Return) {
    408      *resumeAgain = true;
    409      *resumeCompletionKind = completionKind;
    410      resumeValue.set(completionValue);
    411      return true;
    412    }
    413 
    414    // Step 2.
    415    return AsyncGeneratorUnwrapYieldResumptionWithReturn(cx, generator,
    416                                                         completionValue);
    417  }
    418 
    419  // Step 12. Else,
    420  // Step 12.a. Set generator.[[AsyncGeneratorState]] to suspended-yield.
    421  generator->setSuspendedYield();
    422 
    423  // Step 12.b. Remove genContext from the execution context stack and
    424  //            restore the execution context that is at the top of the
    425  //            execution context stack as the running execution context.
    426  // Step 12.c. Let callerContext be the running execution context.
    427  // Step 12.d. Resume callerContext passing undefined. If genContext is ever
    428  //            resumed again, let resumptionValue be the Completion Record with
    429  //            which it is resumed.
    430  // (done as part of bytecode)
    431 
    432  // Step 12.e. Assert: If control reaches here, then genContext is the
    433  //            running execution context again.
    434  // Step 12.f. Return ?
    435  //            AsyncGeneratorUnwrapYieldResumption(resumptionValue).
    436  // (done in AsyncGeneratorResume on the next resume)
    437 
    438  return true;
    439 }
    440 
    441 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
    442 //
    443 // Await in async function
    444 // https://tc39.es/ecma262/#await
    445 //
    446 // Steps 3.c-f.
    447 [[nodiscard]] static bool AsyncGeneratorAwaitedFulfilled(
    448    JSContext* cx, Handle<AsyncGeneratorObject*> generator, HandleValue value) {
    449  MOZ_ASSERT(generator->isExecuting(),
    450             "Await fulfilled when not in 'Executing' state");
    451 
    452  // Step 3.c. Push asyncContext onto the execution context stack; asyncContext
    453  //           is now the running execution context.
    454  // Step 3.d. Resume the suspended evaluation of asyncContext using
    455  //           NormalCompletion(v) as the result of the operation that
    456  //           suspended it.
    457  // Step 3.f. Return undefined.
    458  return AsyncGeneratorResume(cx, generator, CompletionKind::Normal, value);
    459 }
    460 
    461 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
    462 //
    463 // Await in async function
    464 // https://tc39.es/ecma262/#await
    465 //
    466 // Steps 5.c-f.
    467 [[nodiscard]] static bool AsyncGeneratorAwaitedRejected(
    468    JSContext* cx, Handle<AsyncGeneratorObject*> generator,
    469    HandleValue reason) {
    470  MOZ_ASSERT(generator->isExecuting(),
    471             "Await rejected when not in 'Executing' state");
    472 
    473  // Step 5.c. Push asyncContext onto the execution context stack; asyncContext
    474  //           is now the running execution context.
    475  // Step 5.d. Resume the suspended evaluation of asyncContext using
    476  //           ThrowCompletion(reason) as the result of the operation that
    477  //           suspended it.
    478  // Step 5.f. Return undefined.
    479  return AsyncGeneratorResume(cx, generator, CompletionKind::Throw, reason);
    480 }
    481 
    482 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
    483 //
    484 // Await in async function
    485 // https://tc39.es/ecma262/#await
    486 [[nodiscard]] static bool AsyncGeneratorAwait(
    487    JSContext* cx, Handle<AsyncGeneratorObject*> generator, HandleValue value) {
    488  return InternalAsyncGeneratorAwait(
    489      cx, generator, value, PromiseHandler::AsyncGeneratorAwaitedFulfilled,
    490      PromiseHandler::AsyncGeneratorAwaitedRejected);
    491 }
    492 
    493 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
    494 //
    495 // AsyncGeneratorCompleteStep ( generator, completion, done [ , realm ] )
    496 // https://tc39.es/ecma262/#sec-asyncgeneratorcompletestep
    497 //
    498 // "normal" case.
    499 [[nodiscard]] static bool AsyncGeneratorCompleteStepNormal(
    500    JSContext* cx, Handle<AsyncGeneratorObject*> generator, HandleValue value,
    501    bool done) {
    502  // Step 1. Assert: generator.[[AsyncGeneratorQueue]] is not empty.
    503  MOZ_ASSERT(!generator->isQueueEmpty());
    504 
    505  // Step 2. Let next be the first element of generator.[[AsyncGeneratorQueue]].
    506  // Step 3. Remove the first element from generator.[[AsyncGeneratorQueue]].
    507  AsyncGeneratorRequest* next =
    508      AsyncGeneratorObject::dequeueRequest(cx, generator);
    509  if (!next) {
    510    return false;
    511  }
    512 
    513  // Step 4. Let promiseCapability be next.[[Capability]].
    514  Rooted<PromiseObject*> resultPromise(cx, next->promise());
    515 
    516  generator->cacheRequest(next);
    517 
    518  // Step 5. Let value be completion.[[Value]].
    519  // (passed by caller)
    520 
    521  // Step 6. If completion is a throw completion, then
    522  // (done in AsyncGeneratorCompleteStepThrow)
    523 
    524  // Step 7. Else,
    525  // Step 7.a. Assert: completion is a normal completion.
    526 
    527  // Step 7.b. If realm is present, then
    528  // (skipped)
    529 
    530  // Step 7.c. Else,
    531  // Step 7.c.i. Let iteratorResult be CreateIteratorResultObject(value,
    532  //             done).
    533  JSObject* resultObj = CreateIterResultObject(cx, value, done);
    534  if (!resultObj) {
    535    return false;
    536  }
    537 
    538  // Step 7.d. Perform
    539  //           ! Call(promiseCapability.[[Resolve]], undefined,
    540  //                  « iteratorResult »).
    541  // Step 8. Return unused.
    542  RootedValue resultValue(cx, ObjectValue(*resultObj));
    543  return ResolvePromiseInternal(cx, resultPromise, resultValue);
    544 }
    545 
    546 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
    547 //
    548 // AsyncGeneratorCompleteStep ( generator, completion, done [ , realm ] )
    549 // https://tc39.es/ecma262/#sec-asyncgeneratorcompletestep
    550 //
    551 // "throw" case.
    552 [[nodiscard]] static bool AsyncGeneratorCompleteStepThrow(
    553    JSContext* cx, Handle<AsyncGeneratorObject*> generator,
    554    HandleValue exception) {
    555  // Step 1. Assert: generator.[[AsyncGeneratorQueue]] is not empty.
    556  MOZ_ASSERT(!generator->isQueueEmpty());
    557 
    558  // Step 2. Let next be the first element of generator.[[AsyncGeneratorQueue]].
    559  // Step 3. Remove the first element from generator.[[AsyncGeneratorQueue]].
    560  AsyncGeneratorRequest* next =
    561      AsyncGeneratorObject::dequeueRequest(cx, generator);
    562  if (!next) {
    563    return false;
    564  }
    565 
    566  // Step 4. Let promiseCapability be next.[[Capability]].
    567  Rooted<PromiseObject*> resultPromise(cx, next->promise());
    568 
    569  generator->cacheRequest(next);
    570 
    571  // Step 5. Let value be completion.[[Value]].
    572  // (passed by caller)
    573 
    574  // Step 6. If completion is a throw completion, then
    575  // Step 6.a. Perform
    576  //           ! Call(promiseCapability.[[Reject]], undefined, « value »).
    577  // Step 8. Return unused.
    578  return RejectPromiseInternal(cx, resultPromise, exception);
    579 }
    580 
    581 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
    582 //
    583 // AsyncGeneratorAwaitReturn ( generator )
    584 // https://tc39.es/ecma262/#sec-asyncgeneratorawaitreturn
    585 //
    586 // Steps 11.a-e.
    587 [[nodiscard]] static bool AsyncGeneratorAwaitReturnFulfilled(
    588    JSContext* cx, Handle<AsyncGeneratorObject*> generator, HandleValue value) {
    589  // Step 11.a. Assert: generator.[[AsyncGeneratorState]] is draining-queue.
    590  //
    591  // NOTE: We use the implementation-defined state DrainingQueue_AwaitingReturn
    592  //       for the Await during draining-queue, and it's set back to the
    593  //       original draining-queue when the await operation finishes.
    594  MOZ_ASSERT(generator->isDrainingQueue_AwaitingReturn());
    595  generator->setDrainingQueue();
    596 
    597  // Step 11.b. Let result be NormalCompletion(value).
    598  // Step 11.c. Perform AsyncGeneratorCompleteStep(generator, result, true).
    599  if (!AsyncGeneratorCompleteStepNormal(cx, generator, value, true)) {
    600    return false;
    601  }
    602 
    603  MOZ_ASSERT(!generator->isExecuting());
    604  MOZ_ASSERT(!generator->isExecuting_AwaitingYieldReturn());
    605  if (generator->isDrainingQueue_AwaitingReturn()) {
    606    return true;
    607  }
    608 
    609  // Step 11.d. Perform AsyncGeneratorDrainQueue(generator).
    610  // Step 11.e. Return undefined.
    611  return AsyncGeneratorDrainQueue(cx, generator);
    612 }
    613 
    614 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
    615 //
    616 // AsyncGeneratorAwaitReturn ( generator )
    617 // https://tc39.es/ecma262/#sec-asyncgeneratorawaitreturn
    618 //
    619 // Steps 13.a-e.
    620 [[nodiscard]] static bool AsyncGeneratorAwaitReturnRejected(
    621    JSContext* cx, Handle<AsyncGeneratorObject*> generator, HandleValue value) {
    622  // Step 13.a. Assert: generator.[[AsyncGeneratorState]] is draining-queue.
    623  //
    624  // See the comment for AsyncGeneratorAwaitReturnFulfilled.
    625  MOZ_ASSERT(generator->isDrainingQueue_AwaitingReturn());
    626  generator->setDrainingQueue();
    627 
    628  // Step 13.b. Let result be ThrowCompletion(reason).
    629  // Step 13.c. Perform AsyncGeneratorCompleteStep(generator, result, true).
    630  if (!AsyncGeneratorCompleteStepThrow(cx, generator, value)) {
    631    return false;
    632  }
    633 
    634  MOZ_ASSERT(!generator->isExecuting());
    635  MOZ_ASSERT(!generator->isExecuting_AwaitingYieldReturn());
    636  if (generator->isDrainingQueue_AwaitingReturn()) {
    637    return true;
    638  }
    639 
    640  // Step 13.d. Perform AsyncGeneratorDrainQueue(generator).
    641  // Step 13.e. Return undefined.
    642  return AsyncGeneratorDrainQueue(cx, generator);
    643 }
    644 
    645 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
    646 //
    647 // AsyncGeneratorAwaitReturn ( generator )
    648 // https://tc39.es/ecma262/#sec-asyncgeneratorawaitreturn
    649 [[nodiscard]] static bool AsyncGeneratorAwaitReturn(
    650    JSContext* cx, Handle<AsyncGeneratorObject*> generator, HandleValue next) {
    651  // Step 1. Assert: generator.[[AsyncGeneratorState]] is draining-queue.
    652  MOZ_ASSERT(generator->isDrainingQueue());
    653  generator->setDrainingQueue_AwaitingReturn();
    654 
    655  // Step 2. Let queue be generator.[[AsyncGeneratorQueue]].
    656  // Step 3. Assert: queue is not empty.
    657  MOZ_ASSERT(!generator->isQueueEmpty());
    658 
    659  // Step 4. Let next be the first element of queue.
    660  // (passed by caller)
    661 
    662  // Step 5. Let completion be Completion(next.[[Completion]]).
    663  // Step 6. Assert: completion is a return completion.
    664  // (implicit)
    665 
    666  // Step 7. Let promiseCompletion be Completion(PromiseResolve(%Promise%,
    667  //         completion.[[Value]])).
    668 
    669  // Step 9. Assert: promiseCompletion is a normal completion.
    670  // Step 10. Let promise be promiseCompletion.[[Value]].
    671  // Step 11. Let fulfilledClosure be a new Abstract Closure with parameters
    672  //          (value) that captures generator and performs the following steps
    673  //          when called:
    674  // Step 12. Let onFulfilled be CreateBuiltinFunction(fulfilledClosure, 1,
    675  //          "", « »).
    676  // Step 13. Let rejectedClosure be a new Abstract Closure with parameters
    677  //          (reason) that captures generator and performs the following steps
    678  //          when called:
    679  // Step 14. Let onRejected be CreateBuiltinFunction(rejectedClosure, 1, "",
    680  //          « »).
    681  // Step 15. Perform PerformPromiseThen(promise, onFulfilled, onRejected).
    682  // Step 16. Return unused.
    683  if (!InternalAsyncGeneratorAwait(
    684          cx, generator, next,
    685          PromiseHandler::AsyncGeneratorAwaitReturnFulfilled,
    686          PromiseHandler::AsyncGeneratorAwaitReturnRejected)) {
    687    // This branch can be taken with one of the following:
    688    //   * (a) abrupt completion in PromiseResolve at step 7, such as
    689    //         getting `compeltion.[[Value]].constructor` property throws
    690    //   * (b) OOM in PromiseResolve
    691    //   * (c) OOM in PerformPromiseThen
    692    //
    693    // (c) happens after step 8, but OOM is an implementation details and
    694    // we can treat the OOM as if it happened during PromiseResolve,
    695    // and thus performing the step 8 here is okay.
    696    //
    697    // Step 8. If promiseCompletion is an abrupt completion, then
    698 
    699    // Not much we can do about uncatchable exceptions, so just bail.
    700    if (!cx->isExceptionPending()) {
    701      return false;
    702    }
    703 
    704    RootedValue value(cx);
    705    if (!GetAndClearException(cx, &value)) {
    706      return false;
    707    }
    708 
    709    // Step 8.a. Perform AsyncGeneratorCompleteStep(generator,
    710    //           promiseCompletion, true).
    711    if (!AsyncGeneratorCompleteStepThrow(cx, generator, value)) {
    712      return false;
    713    }
    714 
    715    MOZ_ASSERT(!generator->isExecuting());
    716    MOZ_ASSERT(!generator->isExecuting_AwaitingYieldReturn());
    717    if (generator->isDrainingQueue_AwaitingReturn()) {
    718      return true;
    719    }
    720 
    721    // Step 8.b. Perform AsyncGeneratorDrainQueue(generator).
    722    // Step 8.c. Return unused.
    723    return AsyncGeneratorDrainQueue(cx, generator);
    724  }
    725 
    726  return true;
    727 }
    728 
    729 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
    730 //
    731 // AsyncGeneratorDrainQueue ( generator )
    732 // https://tc39.es/ecma262/#sec-asyncgeneratordrainqueue
    733 [[nodiscard]] static bool AsyncGeneratorDrainQueue(
    734    JSContext* cx, Handle<AsyncGeneratorObject*> generator) {
    735  // Step 1. Assert: generator.[[AsyncGeneratorState]] is draining-queue.
    736  //
    737  // NOTE: DrainingQueue_AwaitingReturn shouldn't reach here.
    738  MOZ_ASSERT(generator->isDrainingQueue());
    739 
    740  // Step 2. Let queue be generator.[[AsyncGeneratorQueue]].
    741  // Step 3. Repeat, while queue is not empty,
    742  while (!generator->isQueueEmpty()) {
    743    // Step 3.a. Let next be the first element of queue.
    744    Rooted<AsyncGeneratorRequest*> next(
    745        cx, AsyncGeneratorObject::peekRequest(generator));
    746    if (!next) {
    747      return false;
    748    }
    749 
    750    // Step 3.b. Let completion be Completion(next.[[Completion]]).
    751    CompletionKind completionKind = next->completionKind();
    752 
    753    // Step 3.c. If completion is a return completion, then
    754    if (completionKind == CompletionKind::Return) {
    755      RootedValue value(cx, next->completionValue());
    756 
    757      // Step 3.c.i. Perform AsyncGeneratorAwaitReturn(generator).
    758      // Step 3.c.ii. Return unused.
    759      return AsyncGeneratorAwaitReturn(cx, generator, value);
    760    }
    761 
    762    // Step 3.d. Else,
    763    if (completionKind == CompletionKind::Throw) {
    764      RootedValue value(cx, next->completionValue());
    765 
    766      // Step 3.d.ii. Perform AsyncGeneratorCompleteStep(generator, completion,
    767      //              true).
    768      if (!AsyncGeneratorCompleteStepThrow(cx, generator, value)) {
    769        return false;
    770      }
    771    } else {
    772      // Step 3.d.i. If completion is a normal completion, then
    773      // Step 3.d.i.1. Set completion to NormalCompletion(undefined).
    774      // Step 3.d.ii. Perform AsyncGeneratorCompleteStep(generator, completion,
    775      //              true).
    776      if (!AsyncGeneratorCompleteStepNormal(cx, generator, UndefinedHandleValue,
    777                                            true)) {
    778        return false;
    779      }
    780    }
    781 
    782    MOZ_ASSERT(!generator->isExecuting());
    783    MOZ_ASSERT(!generator->isExecuting_AwaitingYieldReturn());
    784    if (generator->isDrainingQueue_AwaitingReturn()) {
    785      return true;
    786    }
    787  }
    788 
    789  // Step 4. Set generator.[[AsyncGeneratorState]] to completed.
    790  generator->setCompleted();
    791 
    792  // Step 5. Return unused.
    793  return true;
    794 }
    795 
    796 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
    797 //
    798 // AsyncGeneratorValidate ( generator, generatorBrand )
    799 // https://tc39.es/ecma262/#sec-asyncgeneratorvalidate
    800 //
    801 // Testing part.
    802 [[nodiscard]] static bool IsAsyncGeneratorValid(HandleValue asyncGenVal) {
    803  // Step 1. Perform
    804  //         ? RequireInternalSlot(generator, [[AsyncGeneratorContext]]).
    805  // Step 2. Perform
    806  //         ? RequireInternalSlot(generator, [[AsyncGeneratorState]]).
    807  // Step 3. Perform
    808  //         ? RequireInternalSlot(generator, [[AsyncGeneratorQueue]]).
    809  // Step 4. If generator.[[GeneratorBrand]] is not generatorBrand, throw a
    810  //         TypeError exception.
    811  return asyncGenVal.isObject() &&
    812         asyncGenVal.toObject().canUnwrapAs<AsyncGeneratorObject>();
    813 }
    814 
    815 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
    816 //
    817 // AsyncGeneratorValidate ( generator, generatorBrand )
    818 // https://tc39.es/ecma262/#sec-asyncgeneratorvalidate
    819 //
    820 // Throwing part.
    821 [[nodiscard]] static bool AsyncGeneratorValidateThrow(
    822    JSContext* cx, MutableHandleValue result) {
    823  Rooted<PromiseObject*> resultPromise(
    824      cx, CreatePromiseObjectForAsyncGenerator(cx));
    825  if (!resultPromise) {
    826    return false;
    827  }
    828 
    829  RootedValue badGeneratorError(cx);
    830  if (!GetTypeError(cx, JSMSG_NOT_AN_ASYNC_GENERATOR, &badGeneratorError)) {
    831    return false;
    832  }
    833 
    834  if (!RejectPromiseInternal(cx, resultPromise, badGeneratorError)) {
    835    return false;
    836  }
    837 
    838  result.setObject(*resultPromise);
    839  return true;
    840 }
    841 
    842 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
    843 //
    844 // AsyncGeneratorEnqueue ( generator, completion, promiseCapability )
    845 // https://tc39.es/ecma262/#sec-asyncgeneratorenqueue
    846 [[nodiscard]] static bool AsyncGeneratorEnqueue(
    847    JSContext* cx, Handle<AsyncGeneratorObject*> generator,
    848    CompletionKind completionKind, HandleValue completionValue,
    849    Handle<PromiseObject*> resultPromise) {
    850  // Step 1. Let request be
    851  //         AsyncGeneratorRequest { [[Completion]]: completion,
    852  //                                 [[Capability]]: promiseCapability }.
    853  Rooted<AsyncGeneratorRequest*> request(
    854      cx, AsyncGeneratorObject::createRequest(cx, generator, completionKind,
    855                                              completionValue, resultPromise));
    856  if (!request) {
    857    return false;
    858  }
    859 
    860  // Step 2. Append request to generator.[[AsyncGeneratorQueue]].
    861  // Step 3. Return unused.
    862  return AsyncGeneratorObject::enqueueRequest(cx, generator, request);
    863 }
    864 
    865 class MOZ_STACK_CLASS MaybeEnterAsyncGeneratorRealm {
    866  mozilla::Maybe<AutoRealm> ar_;
    867 
    868 public:
    869  MaybeEnterAsyncGeneratorRealm() = default;
    870  ~MaybeEnterAsyncGeneratorRealm() = default;
    871 
    872  // Enter async generator's realm, and wrap the method's argument value if
    873  // necessary.
    874  [[nodiscard]] bool maybeEnterAndWrap(JSContext* cx,
    875                                       Handle<AsyncGeneratorObject*> generator,
    876                                       MutableHandleValue value) {
    877    if (generator->compartment() == cx->compartment()) {
    878      return true;
    879    }
    880 
    881    ar_.emplace(cx, generator);
    882    return cx->compartment()->wrap(cx, value);
    883  }
    884 
    885  // Leave async generator's realm, and wrap the method's result value if
    886  // necessary.
    887  [[nodiscard]] bool maybeLeaveAndWrap(JSContext* cx,
    888                                       MutableHandleValue result) {
    889    if (!ar_) {
    890      return true;
    891    }
    892    ar_.reset();
    893 
    894    return cx->compartment()->wrap(cx, result);
    895  }
    896 };
    897 
    898 [[nodiscard]] static bool AsyncGeneratorMethodSanityCheck(
    899    JSContext* cx, Handle<AsyncGeneratorObject*> generator) {
    900  if (generator->isSuspendedStart() || generator->isSuspendedYield() ||
    901      generator->isCompleted()) {
    902    // The spec assumes the queue is empty when async generator methods are
    903    // called with those state, but our debugger allows calling those methods
    904    // in unexpected state, such as before suspendedStart.
    905    if (MOZ_UNLIKELY(!generator->isQueueEmpty())) {
    906      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    907                                JSMSG_SUSPENDED_QUEUE_NOT_EMPTY);
    908      return false;
    909    }
    910  }
    911 
    912  return true;
    913 }
    914 
    915 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
    916 //
    917 // %AsyncGeneratorPrototype%.next ( value )
    918 // https://tc39.es/ecma262/#sec-asyncgenerator-prototype-next
    919 bool js::AsyncGeneratorNext(JSContext* cx, unsigned argc, Value* vp) {
    920  CallArgs args = CallArgsFromVp(argc, vp);
    921 
    922  // Step 3. Let result be Completion(AsyncGeneratorValidate(generator, empty)).
    923  // Step 4. IfAbruptRejectPromise(result, promiseCapability).
    924  // (reordered)
    925  if (!IsAsyncGeneratorValid(args.thisv())) {
    926    return AsyncGeneratorValidateThrow(cx, args.rval());
    927  }
    928 
    929  // Step 1. Let generator be the this value.
    930  // (implicit)
    931  Rooted<AsyncGeneratorObject*> generator(
    932      cx, &args.thisv().toObject().unwrapAs<AsyncGeneratorObject>());
    933 
    934  MaybeEnterAsyncGeneratorRealm maybeEnterRealm;
    935 
    936  RootedValue completionValue(cx, args.get(0));
    937  if (!maybeEnterRealm.maybeEnterAndWrap(cx, generator, &completionValue)) {
    938    return false;
    939  }
    940 
    941  // Step 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
    942  Rooted<PromiseObject*> resultPromise(
    943      cx, CreatePromiseObjectForAsyncGenerator(cx));
    944  if (!resultPromise) {
    945    return false;
    946  }
    947 
    948  if (!AsyncGeneratorMethodSanityCheck(cx, generator)) {
    949    return false;
    950  }
    951 
    952  // Step 5. Let state be generator.[[AsyncGeneratorState]].
    953  // Step 6. If state is completed, then
    954  if (generator->isCompleted()) {
    955    MOZ_ASSERT(generator->isQueueEmpty());
    956 
    957    // Step 6.a. Let iteratorResult be CreateIteratorResultObject(undefined,
    958    //           true).
    959    JSObject* resultObj =
    960        CreateIterResultObject(cx, UndefinedHandleValue, true);
    961    if (!resultObj) {
    962      return false;
    963    }
    964 
    965    // Step 6.b. Perform ! Call(promiseCapability.[[Resolve]], undefined, «
    966    //           iteratorResult »).
    967    RootedValue resultValue(cx, ObjectValue(*resultObj));
    968    if (!ResolvePromiseInternal(cx, resultPromise, resultValue)) {
    969      return false;
    970    }
    971  } else {
    972    // Step 7. Let completion be NormalCompletion(value).
    973    // Step 8. Perform AsyncGeneratorEnqueue(generator, completion,
    974    //         promiseCapability).
    975    if (!AsyncGeneratorEnqueue(cx, generator, CompletionKind::Normal,
    976                               completionValue, resultPromise)) {
    977      return false;
    978    }
    979 
    980    // Step 9. If state is either suspended-start or suspended-yield, then
    981    if (generator->isSuspendedStart() || generator->isSuspendedYield()) {
    982      MOZ_ASSERT(generator->isQueueLengthOne());
    983 
    984      // Step 9.a. Perform AsyncGeneratorResume(generator, completion).
    985      if (!AsyncGeneratorResume(cx, generator, CompletionKind::Normal,
    986                                completionValue)) {
    987        return false;
    988      }
    989    } else {
    990      // Step 10. Else,
    991      // Step 10.a. Assert: state is either executing or draining-queue.
    992      MOZ_ASSERT(generator->isExecuting() ||
    993                 generator->isExecuting_AwaitingYieldReturn() ||
    994                 generator->isDrainingQueue() ||
    995                 generator->isDrainingQueue_AwaitingReturn());
    996    }
    997  }
    998 
    999  // Step 6.c. Return promiseCapability.[[Promise]].
   1000  // and
   1001  // Step 11. Return promiseCapability.[[Promise]].
   1002  args.rval().setObject(*resultPromise);
   1003 
   1004  return maybeEnterRealm.maybeLeaveAndWrap(cx, args.rval());
   1005 }
   1006 
   1007 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
   1008 //
   1009 // %AsyncGeneratorPrototype%.return ( value )
   1010 // https://tc39.es/ecma262/#sec-asyncgenerator-prototype-return
   1011 bool js::AsyncGeneratorReturn(JSContext* cx, unsigned argc, Value* vp) {
   1012  CallArgs args = CallArgsFromVp(argc, vp);
   1013 
   1014  // Step 3. Let result be Completion(AsyncGeneratorValidate(generator, empty)).
   1015  // Step 4. IfAbruptRejectPromise(result, promiseCapability).
   1016  // (reordered)
   1017  if (!IsAsyncGeneratorValid(args.thisv())) {
   1018    return AsyncGeneratorValidateThrow(cx, args.rval());
   1019  }
   1020 
   1021  // Step 1. Let generator be the this value.
   1022  Rooted<AsyncGeneratorObject*> generator(
   1023      cx, &args.thisv().toObject().unwrapAs<AsyncGeneratorObject>());
   1024 
   1025  MaybeEnterAsyncGeneratorRealm maybeEnterRealm;
   1026 
   1027  RootedValue completionValue(cx, args.get(0));
   1028  if (!maybeEnterRealm.maybeEnterAndWrap(cx, generator, &completionValue)) {
   1029    return false;
   1030  }
   1031 
   1032  // Step 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
   1033  Rooted<PromiseObject*> resultPromise(
   1034      cx, CreatePromiseObjectForAsyncGenerator(cx));
   1035  if (!resultPromise) {
   1036    return false;
   1037  }
   1038 
   1039  if (!AsyncGeneratorMethodSanityCheck(cx, generator)) {
   1040    return false;
   1041  }
   1042 
   1043  // Step 5. Let completion be ReturnCompletion(value).
   1044  // Step 6. Perform AsyncGeneratorEnqueue(generator, completion,
   1045  //         promiseCapability).
   1046  if (!AsyncGeneratorEnqueue(cx, generator, CompletionKind::Return,
   1047                             completionValue, resultPromise)) {
   1048    return false;
   1049  }
   1050 
   1051  // Step 7. Let state be generator.[[AsyncGeneratorState]].
   1052  // Step 8. If state is either suspended-start or completed, then
   1053  if (generator->isSuspendedStart() || generator->isCompleted()) {
   1054    MOZ_ASSERT(generator->isQueueLengthOne());
   1055 
   1056    // Step 8.a. Set generator.[[AsyncGeneratorState]] to draining-queue.
   1057    generator->setDrainingQueue();
   1058 
   1059    // Step 8.b. Perform AsyncGeneratorAwaitReturn(generator).
   1060    if (!AsyncGeneratorAwaitReturn(cx, generator, completionValue)) {
   1061      return false;
   1062    }
   1063  } else if (generator->isSuspendedYield()) {
   1064    // Step 9. Else if state is suspended-yield, then
   1065    MOZ_ASSERT(generator->isQueueLengthOne());
   1066 
   1067    // Step 9.a. Perform AsyncGeneratorResume(generator, completion).
   1068    //
   1069    // https://tc39.es/ecma262/#sec-asyncgeneratorresume
   1070    // AsyncGeneratorResume ( generator, completion )
   1071    //
   1072    // Step 7. Resume the suspended evaluation of genContext using completion as
   1073    //         the result of the operation that suspended it. Let result be the
   1074    //         Completion Record returned by the resumed computation.
   1075    // Step 10. Return unused.
   1076    //
   1077    // AsyncGeneratorYield ( value )
   1078    // https://tc39.es/ecma262/#sec-asyncgeneratoryield
   1079    //
   1080    // Step 12.d. Resume callerContext passing undefined. If genContext is ever
   1081    //            resumed again, let resumptionValue be the Completion Record
   1082    //            with which it is resumed.
   1083    // Step 12.e. Assert: If control reaches here, then genContext is the
   1084    //            running execution context again.
   1085    // Step 12.f. Return ?
   1086    //            AsyncGeneratorUnwrapYieldResumption(resumptionValue).
   1087    //
   1088    if (!AsyncGeneratorUnwrapYieldResumptionWithReturn(cx, generator,
   1089                                                       completionValue)) {
   1090      // The failure path here is for the Await inside
   1091      // AsyncGeneratorUnwrapYieldResumption, where a corrupted Promise is
   1092      // passed and called there.
   1093      //
   1094      // Per spec, the operation should be performed after resuming the
   1095      // generator, but given that we're performing the Await before
   1096      // resuming the generator, we need to handle the special throw completion
   1097      // here.
   1098 
   1099      // For uncatchable exception, there's nothing we can do.
   1100      if (!cx->isExceptionPending()) {
   1101        return false;
   1102      }
   1103 
   1104      // Resume the generator with throw completion, so that it behaves in the
   1105      // same way as the Await throws.
   1106      RootedValue exception(cx);
   1107      if (!GetAndClearException(cx, &exception)) {
   1108        return false;
   1109      }
   1110      if (!AsyncGeneratorResume(cx, generator, CompletionKind::Throw,
   1111                                exception)) {
   1112        return false;
   1113      }
   1114    }
   1115  } else {
   1116    // Step 10. Else,
   1117    // Step 10.a. Assert: state is either executing or draining-queue.
   1118    MOZ_ASSERT(generator->isExecuting() ||
   1119               generator->isExecuting_AwaitingYieldReturn() ||
   1120               generator->isDrainingQueue() ||
   1121               generator->isDrainingQueue_AwaitingReturn());
   1122  }
   1123 
   1124  // Step 11. Return promiseCapability.[[Promise]].
   1125  args.rval().setObject(*resultPromise);
   1126 
   1127  return maybeEnterRealm.maybeLeaveAndWrap(cx, args.rval());
   1128 }
   1129 
   1130 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
   1131 //
   1132 // %AsyncGeneratorPrototype%.throw ( exception )
   1133 // https://tc39.es/ecma262/#sec-asyncgenerator-prototype-throw
   1134 bool js::AsyncGeneratorThrow(JSContext* cx, unsigned argc, Value* vp) {
   1135  CallArgs args = CallArgsFromVp(argc, vp);
   1136 
   1137  // Step 3. Let result be Completion(AsyncGeneratorValidate(generator, empty)).
   1138  // Step 4. IfAbruptRejectPromise(result, promiseCapability).
   1139  // (reordered)
   1140  if (!IsAsyncGeneratorValid(args.thisv())) {
   1141    return AsyncGeneratorValidateThrow(cx, args.rval());
   1142  }
   1143 
   1144  // Step 1. Let generator be the this value.
   1145  Rooted<AsyncGeneratorObject*> generator(
   1146      cx, &args.thisv().toObject().unwrapAs<AsyncGeneratorObject>());
   1147 
   1148  MaybeEnterAsyncGeneratorRealm maybeEnterRealm;
   1149 
   1150  RootedValue completionValue(cx, args.get(0));
   1151  if (!maybeEnterRealm.maybeEnterAndWrap(cx, generator, &completionValue)) {
   1152    return false;
   1153  }
   1154 
   1155  // Step 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
   1156  Rooted<PromiseObject*> resultPromise(
   1157      cx, CreatePromiseObjectForAsyncGenerator(cx));
   1158  if (!resultPromise) {
   1159    return false;
   1160  }
   1161 
   1162  if (!AsyncGeneratorMethodSanityCheck(cx, generator)) {
   1163    return false;
   1164  }
   1165 
   1166  // Step 5. Let state be generator.[[AsyncGeneratorState]].
   1167  // Step 6. If state is suspended-start, then
   1168  if (generator->isSuspendedStart()) {
   1169    // Step 6.a. Set generator.[[AsyncGeneratorState]] to completed.
   1170    // Step 6.b. Set state to completed.
   1171    generator->setCompleted();
   1172  }
   1173 
   1174  // Step 7. If state is completed, then
   1175  if (generator->isCompleted()) {
   1176    MOZ_ASSERT(generator->isQueueEmpty());
   1177 
   1178    // Step 7.a. Perform ! Call(promiseCapability.[[Reject]], undefined, «
   1179    //           exception »).
   1180    if (!RejectPromiseInternal(cx, resultPromise, completionValue)) {
   1181      return false;
   1182    }
   1183  } else {
   1184    // Step 8. Let completion be ThrowCompletion(exception).
   1185    // Step 9. Perform AsyncGeneratorEnqueue(generator, completion,
   1186    //         promiseCapability).
   1187    if (!AsyncGeneratorEnqueue(cx, generator, CompletionKind::Throw,
   1188                               completionValue, resultPromise)) {
   1189      return false;
   1190    }
   1191 
   1192    // Step 10. If state is suspended-yield, then
   1193    if (generator->isSuspendedYield()) {
   1194      MOZ_ASSERT(generator->isQueueLengthOne());
   1195 
   1196      // Step 10.a. Perform AsyncGeneratorResume(generator, completion).
   1197      if (!AsyncGeneratorResume(cx, generator, CompletionKind::Throw,
   1198                                completionValue)) {
   1199        return false;
   1200      }
   1201    } else {
   1202      // Step 11. Else,
   1203      // Step 11.a. Assert: state is either executing or draining-queue.
   1204      MOZ_ASSERT(generator->isExecuting() ||
   1205                 generator->isExecuting_AwaitingYieldReturn() ||
   1206                 generator->isDrainingQueue() ||
   1207                 generator->isDrainingQueue_AwaitingReturn());
   1208    }
   1209  }
   1210 
   1211  // Step 7.b. Return promiseCapability.[[Promise]].
   1212  // and
   1213  // Step 12. Return promiseCapability.[[Promise]].
   1214  args.rval().setObject(*resultPromise);
   1215 
   1216  return maybeEnterRealm.maybeLeaveAndWrap(cx, args.rval());
   1217 }
   1218 
   1219 // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
   1220 //
   1221 // AsyncGeneratorResume ( generator, completion )
   1222 // https://tc39.es/ecma262/#sec-asyncgeneratorresume
   1223 [[nodiscard]] static bool AsyncGeneratorResume(
   1224    JSContext* cx, Handle<AsyncGeneratorObject*> generator,
   1225    CompletionKind completionKind, HandleValue argument) {
   1226  // Given that yield can resume again, we implement it as a loop.
   1227  JS::Rooted<JS::Value> resumeArgument(cx, argument);
   1228  while (true) {
   1229    MOZ_ASSERT(!generator->isClosed(),
   1230               "closed generator when resuming async generator");
   1231    MOZ_ASSERT(generator->isSuspended(),
   1232               "non-suspended generator when resuming async generator");
   1233 
   1234    // Step 1. Assert: generator.[[AsyncGeneratorState]] is either
   1235    //         suspended-start or suspended-yield.
   1236    //
   1237    // NOTE: We're using suspend/resume also for await. and the state can be
   1238    //       anything.
   1239 
   1240    // Step 2. Let genContext be generator.[[AsyncGeneratorContext]].
   1241    // Step 3. Let callerContext be the running execution context.
   1242    // Step 4. Suspend callerContext.
   1243    // (handled in generator)
   1244 
   1245    // Step 5. Set generator.[[AsyncGeneratorState]] to executing.
   1246    generator->setExecuting();
   1247 
   1248    // Step 6. Push genContext onto the execution context stack; genContext is
   1249    //         now the running execution context.
   1250    // Step 7. Resume the suspended evaluation of genContext using completion as
   1251    //         the result of the operation that suspended it. Let result be the
   1252    //         Completion Record returned by the resumed computation.
   1253    // Step 8. Assert: result is never an abrupt completion.
   1254    // Step 9. Assert: When we return here, genContext has already been removed
   1255    //         from the execution context stack and callerContext is the
   1256    //         currently running execution context.
   1257    // Step 10. Return unused.
   1258    Handle<PropertyName*> funName = completionKind == CompletionKind::Normal
   1259                                        ? cx->names().AsyncGeneratorNext
   1260                                    : completionKind == CompletionKind::Throw
   1261                                        ? cx->names().AsyncGeneratorThrow
   1262                                        : cx->names().AsyncGeneratorReturn;
   1263    FixedInvokeArgs<1> args(cx);
   1264    args[0].set(resumeArgument);
   1265    RootedValue thisOrRval(cx, ObjectValue(*generator));
   1266    if (!CallSelfHostedFunction(cx, funName, thisOrRval, args, &thisOrRval)) {
   1267      if (!generator->isClosed()) {
   1268        generator->setClosed(cx);
   1269      }
   1270      return AsyncGeneratorThrown(cx, generator);
   1271    }
   1272 
   1273    if (generator->isAfterAwait()) {
   1274      return AsyncGeneratorAwait(cx, generator, thisOrRval);
   1275    }
   1276 
   1277    if (generator->isAfterYield()) {
   1278      bool resumeAgain = false;
   1279      if (!AsyncGeneratorYield(cx, generator, thisOrRval, &resumeAgain,
   1280                               &completionKind, &resumeArgument)) {
   1281        return false;
   1282      }
   1283      if (resumeAgain) {
   1284        MOZ_ASSERT(completionKind != CompletionKind::Return);
   1285        continue;
   1286      }
   1287      return true;
   1288    }
   1289 
   1290    return AsyncGeneratorReturned(cx, generator, thisOrRval);
   1291  }
   1292 }
   1293 
   1294 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
   1295 /**
   1296 * Explicit Resource Management Proposal
   1297 * 27.1.3.1 %AsyncIteratorPrototype% [ @@asyncDispose ] ( )
   1298 * https://arai-a.github.io/ecma262-compare/?pr=3000&id=sec-%25asynciteratorprototype%25-%40%40asyncdispose
   1299 */
   1300 static bool AsyncIteratorDispose(JSContext* cx, unsigned argc, Value* vp) {
   1301  CallArgs args = CallArgsFromVp(argc, vp);
   1302 
   1303  // Step 1. Let O be the this value.
   1304  JS::Handle<JS::Value> O = args.thisv();
   1305 
   1306  // Step 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
   1307  JS::Rooted<PromiseObject*> promise(cx,
   1308                                     PromiseObject::createSkippingExecutor(cx));
   1309  if (!promise) {
   1310    return false;
   1311  }
   1312 
   1313  // Step 3. Let return be Completion(GetMethod(O, "return")).
   1314  JS::Rooted<JS::Value> returnMethod(cx);
   1315  if (!GetProperty(cx, O, cx->names().return_, &returnMethod)) {
   1316    // Step 4. IfAbruptRejectPromise(return, promiseCapability).
   1317    return AbruptRejectPromise(cx, args, promise, nullptr);
   1318  }
   1319 
   1320  // Step 5. If return is undefined, then
   1321  // As per the spec GetMethod returns undefined if the property is either null
   1322  // or undefined thus here we check for both.
   1323  if (returnMethod.isNullOrUndefined()) {
   1324    // Step 5.a. Perform ! Call(promiseCapability.[[Resolve]], undefined, «
   1325    // undefined »).
   1326    if (!PromiseObject::resolve(cx, promise, JS::UndefinedHandleValue)) {
   1327      return false;
   1328    }
   1329    args.rval().setObject(*promise);
   1330    return true;
   1331  }
   1332 
   1333  // GetMethod also throws a TypeError exception if the function is not callable
   1334  // thus we perform that check here.
   1335  if (!IsCallable(returnMethod)) {
   1336    ReportIsNotFunction(cx, returnMethod);
   1337    return AbruptRejectPromise(cx, args, promise, nullptr);
   1338  }
   1339 
   1340  // Step 6. Else,
   1341  // Step 6.a. Let result be Completion(Call(return, O, « undefined »)).
   1342  JS::Rooted<JS::Value> rval(cx);
   1343  if (!Call(cx, returnMethod, O, JS::UndefinedHandleValue, &rval)) {
   1344    // Step 6.b. IfAbruptRejectPromise(result, promiseCapability).
   1345    return AbruptRejectPromise(cx, args, promise, nullptr);
   1346  }
   1347 
   1348  // Step 6.c-g.
   1349  if (!InternalAsyncIteratorDisposeAwait(cx, rval, promise)) {
   1350    return AbruptRejectPromise(cx, args, promise, nullptr);
   1351  }
   1352 
   1353  // Step 7. Return promiseCapability.[[Promise]].
   1354  args.rval().setObject(*promise);
   1355  return true;
   1356 }
   1357 #endif
   1358 
   1359 static const JSFunctionSpec async_generator_methods[] = {
   1360    JS_FN("next", js::AsyncGeneratorNext, 1, 0),
   1361    JS_FN("throw", js::AsyncGeneratorThrow, 1, 0),
   1362    JS_FN("return", js::AsyncGeneratorReturn, 1, 0),
   1363    JS_FS_END,
   1364 };
   1365 
   1366 static JSObject* CreateAsyncGeneratorFunction(JSContext* cx, JSProtoKey key) {
   1367  RootedObject proto(cx, &cx->global()->getFunctionConstructor());
   1368  Handle<PropertyName*> name = cx->names().AsyncGeneratorFunction;
   1369 
   1370  // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
   1371  //
   1372  // The AsyncGeneratorFunction Constructor
   1373  // https://tc39.es/ecma262/#sec-asyncgeneratorfunction-constructor
   1374  return NewFunctionWithProto(cx, AsyncGeneratorConstructor, 1,
   1375                              FunctionFlags::NATIVE_CTOR, nullptr, name, proto,
   1376                              gc::AllocKind::FUNCTION, TenuredObject);
   1377 }
   1378 
   1379 static JSObject* CreateAsyncGeneratorFunctionPrototype(JSContext* cx,
   1380                                                       JSProtoKey key) {
   1381  return NewTenuredObjectWithFunctionPrototype(cx, cx->global());
   1382 }
   1383 
   1384 static bool AsyncGeneratorFunctionClassFinish(JSContext* cx,
   1385                                              HandleObject asyncGenFunction,
   1386                                              HandleObject asyncGenerator) {
   1387  Handle<GlobalObject*> global = cx->global();
   1388 
   1389  // Change the "constructor" property to non-writable before adding any other
   1390  // properties, so it's still the last property and can be modified without a
   1391  // dictionary-mode transition.
   1392  MOZ_ASSERT(asyncGenerator->as<NativeObject>().getLastProperty().key() ==
   1393             NameToId(cx->names().constructor));
   1394  MOZ_ASSERT(!asyncGenerator->as<NativeObject>().inDictionaryMode());
   1395 
   1396  RootedValue asyncGenFunctionVal(cx, ObjectValue(*asyncGenFunction));
   1397  if (!DefineDataProperty(cx, asyncGenerator, cx->names().constructor,
   1398                          asyncGenFunctionVal, JSPROP_READONLY)) {
   1399    return false;
   1400  }
   1401  MOZ_ASSERT(!asyncGenerator->as<NativeObject>().inDictionaryMode());
   1402 
   1403  RootedObject asyncIterProto(
   1404      cx, GlobalObject::getOrCreateAsyncIteratorPrototype(cx, global));
   1405  if (!asyncIterProto) {
   1406    return false;
   1407  }
   1408 
   1409  // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
   1410  //
   1411  // AsyncGenerator Objects
   1412  // https://tc39.es/ecma262/#sec-asyncgenerator-objects
   1413  RootedObject asyncGenProto(cx, GlobalObject::createBlankPrototypeInheriting(
   1414                                     cx, &PlainObject::class_, asyncIterProto));
   1415  if (!asyncGenProto) {
   1416    return false;
   1417  }
   1418  if (!DefinePropertiesAndFunctions(cx, asyncGenProto, nullptr,
   1419                                    async_generator_methods) ||
   1420      !DefineToStringTag(cx, asyncGenProto, cx->names().AsyncGenerator)) {
   1421    return false;
   1422  }
   1423 
   1424  // ES2026 draft rev bdfd596ffad5aeb2957aed4e1db36be3665c69ec
   1425  //
   1426  // Properties of the AsyncGeneratorFunction Prototype Object
   1427  // https://tc39.es/ecma262/#sec-properties-of-asyncgeneratorfunction-prototype
   1428  if (!LinkConstructorAndPrototype(cx, asyncGenerator, asyncGenProto,
   1429                                   JSPROP_READONLY, JSPROP_READONLY) ||
   1430      !DefineToStringTag(cx, asyncGenerator,
   1431                         cx->names().AsyncGeneratorFunction)) {
   1432    return false;
   1433  }
   1434 
   1435  global->setAsyncGeneratorPrototype(asyncGenProto);
   1436 
   1437  return true;
   1438 }
   1439 
   1440 static const ClassSpec AsyncGeneratorFunctionClassSpec = {
   1441    CreateAsyncGeneratorFunction,
   1442    CreateAsyncGeneratorFunctionPrototype,
   1443    nullptr,
   1444    nullptr,
   1445    nullptr,
   1446    nullptr,
   1447    AsyncGeneratorFunctionClassFinish,
   1448    ClassSpec::DontDefineConstructor,
   1449 };
   1450 
   1451 const JSClass js::AsyncGeneratorFunctionClass = {
   1452    "AsyncGeneratorFunction",
   1453    0,
   1454    JS_NULL_CLASS_OPS,
   1455    &AsyncGeneratorFunctionClassSpec,
   1456 };
   1457 
   1458 [[nodiscard]] bool js::AsyncGeneratorPromiseReactionJob(
   1459    JSContext* cx, PromiseHandler handler,
   1460    Handle<AsyncGeneratorObject*> generator, HandleValue argument) {
   1461  // Await's handlers don't return a value, nor throw any exceptions.
   1462  // They fail only on OOM.
   1463  switch (handler) {
   1464    case PromiseHandler::AsyncGeneratorAwaitedFulfilled:
   1465      return AsyncGeneratorAwaitedFulfilled(cx, generator, argument);
   1466 
   1467    case PromiseHandler::AsyncGeneratorAwaitedRejected:
   1468      return AsyncGeneratorAwaitedRejected(cx, generator, argument);
   1469 
   1470    case PromiseHandler::AsyncGeneratorAwaitReturnFulfilled:
   1471      return AsyncGeneratorAwaitReturnFulfilled(cx, generator, argument);
   1472 
   1473    case PromiseHandler::AsyncGeneratorAwaitReturnRejected:
   1474      return AsyncGeneratorAwaitReturnRejected(cx, generator, argument);
   1475 
   1476    case PromiseHandler::AsyncGeneratorYieldReturnAwaitedFulfilled:
   1477      return AsyncGeneratorYieldReturnAwaitedFulfilled(cx, generator, argument);
   1478 
   1479    case PromiseHandler::AsyncGeneratorYieldReturnAwaitedRejected:
   1480      return AsyncGeneratorYieldReturnAwaitedRejected(cx, generator, argument);
   1481 
   1482    default:
   1483      MOZ_CRASH("Bad handler in AsyncGeneratorPromiseReactionJob");
   1484  }
   1485 }
   1486 
   1487 // ---------------------
   1488 // AsyncFromSyncIterator
   1489 // ---------------------
   1490 
   1491 const JSClass AsyncFromSyncIteratorObject::class_ = {
   1492    "AsyncFromSyncIteratorObject",
   1493    JSCLASS_HAS_RESERVED_SLOTS(AsyncFromSyncIteratorObject::Slots),
   1494 };
   1495 
   1496 /*
   1497 * ES2024 draft rev 53454a9a596d90473d2152ef04656d605162cd4c
   1498 *
   1499 * CreateAsyncFromSyncIterator ( syncIteratorRecord )
   1500 * https://tc39.es/ecma262/#sec-createasyncfromsynciterator
   1501 */
   1502 JSObject* js::CreateAsyncFromSyncIterator(JSContext* cx, HandleObject iter,
   1503                                          HandleValue nextMethod) {
   1504  // Steps 1-5.
   1505  return AsyncFromSyncIteratorObject::create(cx, iter, nextMethod);
   1506 }
   1507 
   1508 /*
   1509 * ES2024 draft rev 53454a9a596d90473d2152ef04656d605162cd4c
   1510 *
   1511 * CreateAsyncFromSyncIterator ( syncIteratorRecord )
   1512 * https://tc39.es/ecma262/#sec-createasyncfromsynciterator
   1513 */
   1514 /* static */
   1515 JSObject* AsyncFromSyncIteratorObject::create(JSContext* cx, HandleObject iter,
   1516                                              HandleValue nextMethod) {
   1517  // Step 1. Let asyncIterator be
   1518  //         OrdinaryObjectCreate(%AsyncFromSyncIteratorPrototype%, «
   1519  //         [[SyncIteratorRecord]] »).
   1520  RootedObject proto(cx,
   1521                     GlobalObject::getOrCreateAsyncFromSyncIteratorPrototype(
   1522                         cx, cx->global()));
   1523  if (!proto) {
   1524    return nullptr;
   1525  }
   1526 
   1527  AsyncFromSyncIteratorObject* asyncIter =
   1528      NewObjectWithGivenProto<AsyncFromSyncIteratorObject>(cx, proto);
   1529  if (!asyncIter) {
   1530    return nullptr;
   1531  }
   1532 
   1533  // Step 3. Let nextMethod be ! Get(asyncIterator, "next").
   1534  // (done in caller)
   1535 
   1536  // Step 2. Set asyncIterator.[[SyncIteratorRecord]] to syncIteratorRecord.
   1537  // Step 4. Let iteratorRecord be the Iterator Record { [[Iterator]]:
   1538  //         asyncIterator, [[NextMethod]]: nextMethod, [[Done]]: false }.
   1539  asyncIter->init(iter, nextMethod);
   1540 
   1541  // Step 5. Return iteratorRecord.
   1542  return asyncIter;
   1543 }
   1544 
   1545 /**
   1546 * ES2024 draft rev 53454a9a596d90473d2152ef04656d605162cd4c
   1547 *
   1548 * %AsyncFromSyncIteratorPrototype%.next ( [ value ] )
   1549 * https://tc39.es/ecma262/#sec-%asyncfromsynciteratorprototype%.next
   1550 */
   1551 static bool AsyncFromSyncIteratorNext(JSContext* cx, unsigned argc, Value* vp) {
   1552  CallArgs args = CallArgsFromVp(argc, vp);
   1553  return AsyncFromSyncIteratorMethod(cx, args, CompletionKind::Normal);
   1554 }
   1555 
   1556 /**
   1557 * ES2024 draft rev 53454a9a596d90473d2152ef04656d605162cd4c
   1558 *
   1559 * %AsyncFromSyncIteratorPrototype%.return ( [ value ] )
   1560 * https://tc39.es/ecma262/#sec-%asyncfromsynciteratorprototype%.return
   1561 */
   1562 static bool AsyncFromSyncIteratorReturn(JSContext* cx, unsigned argc,
   1563                                        Value* vp) {
   1564  CallArgs args = CallArgsFromVp(argc, vp);
   1565  return AsyncFromSyncIteratorMethod(cx, args, CompletionKind::Return);
   1566 }
   1567 
   1568 /**
   1569 * ES2024 draft rev 53454a9a596d90473d2152ef04656d605162cd4c
   1570 *
   1571 * %AsyncFromSyncIteratorPrototype%.throw ( [ value ] )
   1572 * https://tc39.es/ecma262/#sec-%asyncfromsynciteratorprototype%.throw
   1573 */
   1574 static bool AsyncFromSyncIteratorThrow(JSContext* cx, unsigned argc,
   1575                                       Value* vp) {
   1576  CallArgs args = CallArgsFromVp(argc, vp);
   1577  return AsyncFromSyncIteratorMethod(cx, args, CompletionKind::Throw);
   1578 }
   1579 
   1580 static const JSFunctionSpec async_from_sync_iter_methods[] = {
   1581    JS_FN("next", AsyncFromSyncIteratorNext, 1, 0),
   1582    JS_FN("throw", AsyncFromSyncIteratorThrow, 1, 0),
   1583    JS_FN("return", AsyncFromSyncIteratorReturn, 1, 0),
   1584    JS_FS_END,
   1585 };
   1586 
   1587 bool GlobalObject::initAsyncFromSyncIteratorProto(
   1588    JSContext* cx, Handle<GlobalObject*> global) {
   1589  if (global->hasBuiltinProto(ProtoKind::AsyncFromSyncIteratorProto)) {
   1590    return true;
   1591  }
   1592 
   1593  RootedObject asyncIterProto(
   1594      cx, GlobalObject::getOrCreateAsyncIteratorPrototype(cx, global));
   1595  if (!asyncIterProto) {
   1596    return false;
   1597  }
   1598 
   1599  // ES2024 draft rev 53454a9a596d90473d2152ef04656d605162cd4c
   1600  //
   1601  // The %AsyncFromSyncIteratorPrototype% Object
   1602  // https://tc39.es/ecma262/#sec-%asyncfromsynciteratorprototype%-object
   1603  RootedObject asyncFromSyncIterProto(
   1604      cx, GlobalObject::createBlankPrototypeInheriting(cx, &PlainObject::class_,
   1605                                                       asyncIterProto));
   1606  if (!asyncFromSyncIterProto) {
   1607    return false;
   1608  }
   1609  if (!DefinePropertiesAndFunctions(cx, asyncFromSyncIterProto, nullptr,
   1610                                    async_from_sync_iter_methods) ||
   1611      !DefineToStringTag(cx, asyncFromSyncIterProto,
   1612                         cx->names().Async_from_Sync_Iterator_)) {
   1613    return false;
   1614  }
   1615 
   1616  global->initBuiltinProto(ProtoKind::AsyncFromSyncIteratorProto,
   1617                           asyncFromSyncIterProto);
   1618  return true;
   1619 }
   1620 
   1621 // -------------
   1622 // AsyncIterator
   1623 // -------------
   1624 
   1625 static const JSFunctionSpec async_iterator_proto_methods[] = {
   1626    JS_SELF_HOSTED_SYM_FN(asyncIterator, "AsyncIteratorIdentity", 0, 0),
   1627 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
   1628    JS_SYM_FN(asyncDispose, AsyncIteratorDispose, 0, 0),
   1629 #endif
   1630    JS_FS_END,
   1631 };
   1632 
   1633 static const JSFunctionSpec async_iterator_proto_methods_with_helpers[] = {
   1634    JS_SELF_HOSTED_FN("map", "AsyncIteratorMap", 1, 0),
   1635    JS_SELF_HOSTED_FN("filter", "AsyncIteratorFilter", 1, 0),
   1636    JS_SELF_HOSTED_FN("take", "AsyncIteratorTake", 1, 0),
   1637    JS_SELF_HOSTED_FN("drop", "AsyncIteratorDrop", 1, 0),
   1638    JS_SELF_HOSTED_FN("asIndexedPairs", "AsyncIteratorAsIndexedPairs", 0, 0),
   1639    JS_SELF_HOSTED_FN("flatMap", "AsyncIteratorFlatMap", 1, 0),
   1640    JS_SELF_HOSTED_FN("reduce", "AsyncIteratorReduce", 1, 0),
   1641    JS_SELF_HOSTED_FN("toArray", "AsyncIteratorToArray", 0, 0),
   1642    JS_SELF_HOSTED_FN("forEach", "AsyncIteratorForEach", 1, 0),
   1643    JS_SELF_HOSTED_FN("some", "AsyncIteratorSome", 1, 0),
   1644    JS_SELF_HOSTED_FN("every", "AsyncIteratorEvery", 1, 0),
   1645    JS_SELF_HOSTED_FN("find", "AsyncIteratorFind", 1, 0),
   1646    JS_SELF_HOSTED_SYM_FN(asyncIterator, "AsyncIteratorIdentity", 0, 0),
   1647 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
   1648    JS_SYM_FN(asyncDispose, AsyncIteratorDispose, 0, 0),
   1649 #endif
   1650    JS_FS_END,
   1651 };
   1652 
   1653 bool GlobalObject::initAsyncIteratorProto(JSContext* cx,
   1654                                          Handle<GlobalObject*> global) {
   1655  if (global->hasBuiltinProto(ProtoKind::AsyncIteratorProto)) {
   1656    return true;
   1657  }
   1658 
   1659  // 25.1.3 The %AsyncIteratorPrototype% Object
   1660  RootedObject asyncIterProto(
   1661      cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
   1662  if (!asyncIterProto) {
   1663    return false;
   1664  }
   1665  if (!DefinePropertiesAndFunctions(cx, asyncIterProto, nullptr,
   1666                                    async_iterator_proto_methods)) {
   1667    return false;
   1668  }
   1669 
   1670  global->initBuiltinProto(ProtoKind::AsyncIteratorProto, asyncIterProto);
   1671  return true;
   1672 }
   1673 
   1674 // https://tc39.es/proposal-iterator-helpers/#sec-asynciterator as of revision
   1675 // 8f10db5.
   1676 static bool AsyncIteratorConstructor(JSContext* cx, unsigned argc, Value* vp) {
   1677  CallArgs args = CallArgsFromVp(argc, vp);
   1678 
   1679  // Step 1.
   1680  if (!ThrowIfNotConstructing(cx, args, "AsyncIterator")) {
   1681    return false;
   1682  }
   1683  // Throw TypeError if NewTarget is the active function object, preventing the
   1684  // Iterator constructor from being used directly.
   1685  if (args.callee() == args.newTarget().toObject()) {
   1686    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
   1687                              JSMSG_BOGUS_CONSTRUCTOR, "AsyncIterator");
   1688    return false;
   1689  }
   1690 
   1691  // Step 2.
   1692  RootedObject proto(cx);
   1693  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_AsyncIterator,
   1694                                          &proto)) {
   1695    return false;
   1696  }
   1697 
   1698  JSObject* obj = NewObjectWithClassProto<AsyncIteratorObject>(cx, proto);
   1699  if (!obj) {
   1700    return false;
   1701  }
   1702 
   1703  args.rval().setObject(*obj);
   1704  return true;
   1705 }
   1706 
   1707 static const ClassSpec AsyncIteratorObjectClassSpec = {
   1708    GenericCreateConstructor<AsyncIteratorConstructor, 0,
   1709                             gc::AllocKind::FUNCTION>,
   1710    GenericCreatePrototype<AsyncIteratorObject>,
   1711    nullptr,
   1712    nullptr,
   1713    async_iterator_proto_methods_with_helpers,
   1714    nullptr,
   1715    nullptr,
   1716 };
   1717 
   1718 const JSClass AsyncIteratorObject::class_ = {
   1719    "AsyncIterator",
   1720    JSCLASS_HAS_CACHED_PROTO(JSProto_AsyncIterator),
   1721    JS_NULL_CLASS_OPS,
   1722    &AsyncIteratorObjectClassSpec,
   1723 };
   1724 
   1725 const JSClass AsyncIteratorObject::protoClass_ = {
   1726    "AsyncIterator.prototype",
   1727    JSCLASS_HAS_CACHED_PROTO(JSProto_AsyncIterator),
   1728    JS_NULL_CLASS_OPS,
   1729    &AsyncIteratorObjectClassSpec,
   1730 };
   1731 
   1732 // Iterator Helper proposal
   1733 static const JSFunctionSpec async_iterator_helper_methods[] = {
   1734    JS_SELF_HOSTED_FN("next", "AsyncIteratorHelperNext", 1, 0),
   1735    JS_SELF_HOSTED_FN("return", "AsyncIteratorHelperReturn", 1, 0),
   1736    JS_SELF_HOSTED_FN("throw", "AsyncIteratorHelperThrow", 1, 0),
   1737    JS_FS_END,
   1738 };
   1739 
   1740 static const JSClass AsyncIteratorHelperPrototypeClass = {
   1741    "Async Iterator Helper",
   1742    0,
   1743 };
   1744 
   1745 const JSClass AsyncIteratorHelperObject::class_ = {
   1746    "Async Iterator Helper",
   1747    JSCLASS_HAS_RESERVED_SLOTS(AsyncIteratorHelperObject::SlotCount),
   1748 };
   1749 
   1750 /* static */
   1751 NativeObject* GlobalObject::getOrCreateAsyncIteratorHelperPrototype(
   1752    JSContext* cx, Handle<GlobalObject*> global) {
   1753  return MaybeNativeObject(
   1754      getOrCreateBuiltinProto(cx, global, ProtoKind::AsyncIteratorHelperProto,
   1755                              initAsyncIteratorHelperProto));
   1756 }
   1757 
   1758 /* static */
   1759 bool GlobalObject::initAsyncIteratorHelperProto(JSContext* cx,
   1760                                                Handle<GlobalObject*> global) {
   1761  if (global->hasBuiltinProto(ProtoKind::AsyncIteratorHelperProto)) {
   1762    return true;
   1763  }
   1764 
   1765  RootedObject asyncIterProto(
   1766      cx, GlobalObject::getOrCreateAsyncIteratorPrototype(cx, global));
   1767  if (!asyncIterProto) {
   1768    return false;
   1769  }
   1770 
   1771  RootedObject asyncIteratorHelperProto(
   1772      cx, GlobalObject::createBlankPrototypeInheriting(
   1773              cx, &AsyncIteratorHelperPrototypeClass, asyncIterProto));
   1774  if (!asyncIteratorHelperProto) {
   1775    return false;
   1776  }
   1777  if (!DefinePropertiesAndFunctions(cx, asyncIteratorHelperProto, nullptr,
   1778                                    async_iterator_helper_methods)) {
   1779    return false;
   1780  }
   1781 
   1782  global->initBuiltinProto(ProtoKind::AsyncIteratorHelperProto,
   1783                           asyncIteratorHelperProto);
   1784  return true;
   1785 }
   1786 
   1787 AsyncIteratorHelperObject* js::NewAsyncIteratorHelper(JSContext* cx) {
   1788  RootedObject proto(cx, GlobalObject::getOrCreateAsyncIteratorHelperPrototype(
   1789                             cx, cx->global()));
   1790  if (!proto) {
   1791    return nullptr;
   1792  }
   1793  return NewObjectWithGivenProto<AsyncIteratorHelperObject>(cx, proto);
   1794 }