LCOV - code coverage report
Current view: top level - src/builtins - builtins-async-generator-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 252 254 99.2 %
Date: 2019-04-17 Functions: 46 48 95.8 %

          Line data    Source code
       1             : // Copyright 2017 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/builtins/builtins-async-gen.h"
       6             : #include "src/builtins/builtins-utils-gen.h"
       7             : #include "src/builtins/builtins.h"
       8             : #include "src/code-factory.h"
       9             : #include "src/code-stub-assembler.h"
      10             : #include "src/frames-inl.h"
      11             : #include "src/objects/js-generator.h"
      12             : #include "src/objects/js-promise.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : 
      17             : using compiler::Node;
      18             : 
      19             : namespace {
      20             : 
      21         896 : class AsyncGeneratorBuiltinsAssembler : public AsyncBuiltinsAssembler {
      22             :  public:
      23             :   explicit AsyncGeneratorBuiltinsAssembler(CodeAssemblerState* state)
      24             :       : AsyncBuiltinsAssembler(state) {}
      25             : 
      26         168 :   inline Node* TaggedIsAsyncGenerator(Node* tagged_object) {
      27         168 :     TNode<BoolT> if_notsmi = TaggedIsNotSmi(tagged_object);
      28         336 :     return Select<BoolT>(if_notsmi,
      29             :                          [=] {
      30             :                            return HasInstanceType(
      31         504 :                                tagged_object, JS_ASYNC_GENERATOR_OBJECT_TYPE);
      32         168 :                          },
      33         504 :                          [=] { return if_notsmi; });
      34             :   }
      35             :   inline Node* LoadGeneratorState(Node* const generator) {
      36          56 :     return LoadObjectField(generator, JSGeneratorObject::kContinuationOffset);
      37             :   }
      38             : 
      39         168 :   inline TNode<BoolT> IsGeneratorStateClosed(SloppyTNode<Smi> const state) {
      40         168 :     return SmiEqual(state, SmiConstant(JSGeneratorObject::kGeneratorClosed));
      41             :   }
      42             :   inline TNode<BoolT> IsGeneratorClosed(Node* const generator) {
      43             :     return IsGeneratorStateClosed(LoadGeneratorState(generator));
      44             :   }
      45             : 
      46             :   inline TNode<BoolT> IsGeneratorStateSuspended(SloppyTNode<Smi> const state) {
      47             :     return SmiGreaterThanOrEqual(state, SmiConstant(0));
      48             :   }
      49             : 
      50             :   inline TNode<BoolT> IsGeneratorSuspended(Node* const generator) {
      51             :     return IsGeneratorStateSuspended(LoadGeneratorState(generator));
      52             :   }
      53             : 
      54          56 :   inline TNode<BoolT> IsGeneratorStateSuspendedAtStart(
      55             :       SloppyTNode<Smi> const state) {
      56          56 :     return SmiEqual(state, SmiConstant(0));
      57             :   }
      58             : 
      59             :   inline TNode<BoolT> IsGeneratorStateNotExecuting(
      60             :       SloppyTNode<Smi> const state) {
      61             :     return SmiNotEqual(state,
      62             :                        SmiConstant(JSGeneratorObject::kGeneratorExecuting));
      63             :   }
      64             :   inline TNode<BoolT> IsGeneratorNotExecuting(Node* const generator) {
      65             :     return IsGeneratorStateNotExecuting(LoadGeneratorState(generator));
      66             :   }
      67             : 
      68          56 :   inline TNode<BoolT> IsGeneratorAwaiting(Node* const generator) {
      69             :     TNode<Object> is_generator_awaiting =
      70          56 :         LoadObjectField(generator, JSAsyncGeneratorObject::kIsAwaitingOffset);
      71         112 :     return WordEqual(is_generator_awaiting, SmiConstant(1));
      72             :   }
      73             : 
      74         224 :   inline void SetGeneratorAwaiting(Node* const generator) {
      75             :     CSA_ASSERT(this, Word32BinaryNot(IsGeneratorAwaiting(generator)));
      76         224 :     StoreObjectFieldNoWriteBarrier(
      77         448 :         generator, JSAsyncGeneratorObject::kIsAwaitingOffset, SmiConstant(1));
      78             :     CSA_ASSERT(this, IsGeneratorAwaiting(generator));
      79         224 :   }
      80             : 
      81         336 :   inline void SetGeneratorNotAwaiting(Node* const generator) {
      82             :     CSA_ASSERT(this, IsGeneratorAwaiting(generator));
      83         336 :     StoreObjectFieldNoWriteBarrier(
      84         672 :         generator, JSAsyncGeneratorObject::kIsAwaitingOffset, SmiConstant(0));
      85             :     CSA_ASSERT(this, Word32BinaryNot(IsGeneratorAwaiting(generator)));
      86         336 :   }
      87             : 
      88          56 :   inline void CloseGenerator(Node* const generator) {
      89          56 :     StoreObjectFieldNoWriteBarrier(
      90             :         generator, JSGeneratorObject::kContinuationOffset,
      91         112 :         SmiConstant(JSGeneratorObject::kGeneratorClosed));
      92          56 :   }
      93             : 
      94             :   inline Node* IsFastJSIterResult(Node* const value, Node* const context) {
      95             :     CSA_ASSERT(this, TaggedIsNotSmi(value));
      96             :     Node* const native_context = LoadNativeContext(context);
      97             :     return WordEqual(
      98             :         LoadMap(value),
      99             :         LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX));
     100             :   }
     101             : 
     102             :   inline Node* LoadFirstAsyncGeneratorRequestFromQueue(Node* const generator) {
     103         224 :     return LoadObjectField(generator, JSAsyncGeneratorObject::kQueueOffset);
     104             :   }
     105             : 
     106             :   inline Node* LoadResumeTypeFromAsyncGeneratorRequest(Node* const request) {
     107             :     return LoadObjectField(request, AsyncGeneratorRequest::kResumeModeOffset);
     108             :   }
     109             : 
     110             :   inline Node* LoadPromiseFromAsyncGeneratorRequest(Node* const request) {
     111         112 :     return LoadObjectField(request, AsyncGeneratorRequest::kPromiseOffset);
     112             :   }
     113             : 
     114             :   inline Node* LoadValueFromAsyncGeneratorRequest(Node* const request) {
     115             :     return LoadObjectField(request, AsyncGeneratorRequest::kValueOffset);
     116             :   }
     117             : 
     118          56 :   inline TNode<BoolT> IsAbruptResumeType(SloppyTNode<Smi> const resume_type) {
     119         112 :     return SmiNotEqual(resume_type, SmiConstant(JSGeneratorObject::kNext));
     120             :   }
     121             : 
     122             :   void AsyncGeneratorEnqueue(CodeStubArguments* args, Node* context,
     123             :                              Node* generator, Node* value,
     124             :                              JSAsyncGeneratorObject::ResumeMode resume_mode,
     125             :                              const char* method_name);
     126             : 
     127             :   Node* TakeFirstAsyncGeneratorRequestFromQueue(Node* generator);
     128             :   Node* TakeFirstAsyncGeneratorRequestFromQueueIfPresent(Node* generator,
     129             :                                                          Label* if_not_present);
     130             :   void AddAsyncGeneratorRequestToQueue(Node* generator, Node* request);
     131             : 
     132             :   Node* AllocateAsyncGeneratorRequest(
     133             :       JSAsyncGeneratorObject::ResumeMode resume_mode, Node* resume_value,
     134             :       Node* promise);
     135             : 
     136             :   // Shared implementation of the catchable and uncatchable variations of Await
     137             :   // for AsyncGenerators.
     138             :   template <typename Descriptor>
     139             :   void AsyncGeneratorAwait(bool is_catchable);
     140             :   void AsyncGeneratorAwaitResumeClosure(
     141             :       Node* context, Node* value,
     142             :       JSAsyncGeneratorObject::ResumeMode resume_mode);
     143             : };
     144             : 
     145             : // Shared implementation for the 3 Async Iterator protocol methods of Async
     146             : // Generators.
     147         168 : void AsyncGeneratorBuiltinsAssembler::AsyncGeneratorEnqueue(
     148             :     CodeStubArguments* args, Node* context, Node* generator, Node* value,
     149             :     JSAsyncGeneratorObject::ResumeMode resume_mode, const char* method_name) {
     150             :   // AsyncGeneratorEnqueue produces a new Promise, and appends it to the list
     151             :   // of async generator requests to be executed. If the generator is not
     152             :   // presently executing, then this method will loop through, processing each
     153             :   // request from front to back.
     154             :   // This loop resides in AsyncGeneratorResumeNext.
     155         168 :   Node* promise = AllocateAndInitJSPromise(context);
     156             : 
     157         336 :   Label enqueue(this), if_receiverisincompatible(this, Label::kDeferred);
     158             : 
     159         336 :   Branch(TaggedIsAsyncGenerator(generator), &enqueue,
     160         168 :          &if_receiverisincompatible);
     161             : 
     162         168 :   BIND(&enqueue);
     163             :   {
     164         168 :     Label done(this);
     165             :     Node* const req =
     166         168 :         AllocateAsyncGeneratorRequest(resume_mode, value, promise);
     167             : 
     168         168 :     AddAsyncGeneratorRequestToQueue(generator, req);
     169             : 
     170             :     // Let state be generator.[[AsyncGeneratorState]]
     171             :     // If state is not "executing", then
     172             :     //     Perform AsyncGeneratorResumeNext(Generator)
     173             :     // Check if the {receiver} is running or already closed.
     174         168 :     TNode<Smi> continuation = CAST(LoadGeneratorState(generator));
     175             : 
     176         336 :     GotoIf(SmiEqual(continuation,
     177         168 :                     SmiConstant(JSAsyncGeneratorObject::kGeneratorExecuting)),
     178         168 :            &done);
     179             : 
     180         168 :     CallBuiltin(Builtins::kAsyncGeneratorResumeNext, context, generator);
     181             : 
     182         168 :     Goto(&done);
     183         168 :     BIND(&done);
     184         168 :     args->PopAndReturn(promise);
     185             :   }
     186             : 
     187         168 :   BIND(&if_receiverisincompatible);
     188             :   {
     189             :     Node* const error =
     190         168 :         MakeTypeError(MessageTemplate::kIncompatibleMethodReceiver, context,
     191         168 :                       StringConstant(method_name), generator);
     192             : 
     193             :     CallBuiltin(Builtins::kRejectPromise, context, promise, error,
     194         336 :                 TrueConstant());
     195         168 :     args->PopAndReturn(promise);
     196             :   }
     197         168 : }
     198             : 
     199         168 : Node* AsyncGeneratorBuiltinsAssembler::AllocateAsyncGeneratorRequest(
     200             :     JSAsyncGeneratorObject::ResumeMode resume_mode, Node* resume_value,
     201             :     Node* promise) {
     202             :   CSA_SLOW_ASSERT(this, HasInstanceType(promise, JS_PROMISE_TYPE));
     203         336 :   Node* request = Allocate(AsyncGeneratorRequest::kSize);
     204         168 :   StoreMapNoWriteBarrier(request, RootIndex::kAsyncGeneratorRequestMap);
     205             :   StoreObjectFieldNoWriteBarrier(request, AsyncGeneratorRequest::kNextOffset,
     206         336 :                                  UndefinedConstant());
     207             :   StoreObjectFieldNoWriteBarrier(request,
     208             :                                  AsyncGeneratorRequest::kResumeModeOffset,
     209         336 :                                  SmiConstant(resume_mode));
     210             :   StoreObjectFieldNoWriteBarrier(request, AsyncGeneratorRequest::kValueOffset,
     211         168 :                                  resume_value);
     212             :   StoreObjectFieldNoWriteBarrier(request, AsyncGeneratorRequest::kPromiseOffset,
     213         168 :                                  promise);
     214             :   StoreObjectFieldRoot(request, AsyncGeneratorRequest::kNextOffset,
     215         168 :                        RootIndex::kUndefinedValue);
     216         168 :   return request;
     217             : }
     218             : 
     219         168 : void AsyncGeneratorBuiltinsAssembler::AsyncGeneratorAwaitResumeClosure(
     220             :     Node* context, Node* value,
     221             :     JSAsyncGeneratorObject::ResumeMode resume_mode) {
     222         336 :   Node* const generator = LoadContextElement(context, Context::EXTENSION_INDEX);
     223             :   CSA_SLOW_ASSERT(this, TaggedIsAsyncGenerator(generator));
     224             : 
     225         168 :   SetGeneratorNotAwaiting(generator);
     226             : 
     227             :   CSA_SLOW_ASSERT(this, IsGeneratorSuspended(generator));
     228             : 
     229             :   // Remember the {resume_mode} for the {generator}.
     230             :   StoreObjectFieldNoWriteBarrier(generator,
     231             :                                  JSGeneratorObject::kResumeModeOffset,
     232         336 :                                  SmiConstant(resume_mode));
     233             : 
     234         336 :   CallStub(CodeFactory::ResumeGenerator(isolate()), context, value, generator);
     235             : 
     236         168 :   TailCallBuiltin(Builtins::kAsyncGeneratorResumeNext, context, generator);
     237         168 : }
     238             : 
     239             : template <typename Descriptor>
     240         112 : void AsyncGeneratorBuiltinsAssembler::AsyncGeneratorAwait(bool is_catchable) {
     241             :   TNode<JSAsyncGeneratorObject> async_generator_object =
     242         112 :       CAST(Parameter(Descriptor::kAsyncGeneratorObject));
     243         112 :   TNode<Object> value = CAST(Parameter(Descriptor::kValue));
     244         112 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     245             : 
     246             :   TNode<AsyncGeneratorRequest> request =
     247             :       CAST(LoadFirstAsyncGeneratorRequestFromQueue(async_generator_object));
     248             :   TNode<JSPromise> outer_promise = LoadObjectField<JSPromise>(
     249             :       request, AsyncGeneratorRequest::kPromiseOffset);
     250             : 
     251             :   const int resolve_index = Context::ASYNC_GENERATOR_AWAIT_RESOLVE_SHARED_FUN;
     252             :   const int reject_index = Context::ASYNC_GENERATOR_AWAIT_REJECT_SHARED_FUN;
     253             : 
     254         112 :   SetGeneratorAwaiting(async_generator_object);
     255         112 :   Await(context, async_generator_object, value, outer_promise, resolve_index,
     256             :         reject_index, is_catchable);
     257         224 :   Return(UndefinedConstant());
     258         112 : }
     259             : 
     260         168 : void AsyncGeneratorBuiltinsAssembler::AddAsyncGeneratorRequestToQueue(
     261             :     Node* generator, Node* request) {
     262         336 :   VARIABLE(var_current, MachineRepresentation::kTagged);
     263         168 :   Label empty(this), loop(this, &var_current), done(this);
     264             : 
     265             :   var_current.Bind(
     266         336 :       LoadObjectField(generator, JSAsyncGeneratorObject::kQueueOffset));
     267         504 :   Branch(IsUndefined(var_current.value()), &empty, &loop);
     268             : 
     269         168 :   BIND(&empty);
     270             :   {
     271         168 :     StoreObjectField(generator, JSAsyncGeneratorObject::kQueueOffset, request);
     272         168 :     Goto(&done);
     273             :   }
     274             : 
     275         168 :   BIND(&loop);
     276             :   {
     277         168 :     Label loop_next(this), next_empty(this);
     278         168 :     Node* current = var_current.value();
     279             :     Node* next = LoadObjectField(current, AsyncGeneratorRequest::kNextOffset);
     280             : 
     281         336 :     Branch(IsUndefined(next), &next_empty, &loop_next);
     282         168 :     BIND(&next_empty);
     283             :     {
     284         168 :       StoreObjectField(current, AsyncGeneratorRequest::kNextOffset, request);
     285         168 :       Goto(&done);
     286             :     }
     287             : 
     288         168 :     BIND(&loop_next);
     289             :     {
     290         168 :       var_current.Bind(next);
     291         168 :       Goto(&loop);
     292             :     }
     293             :   }
     294         168 :   BIND(&done);
     295         168 : }
     296             : 
     297         112 : Node* AsyncGeneratorBuiltinsAssembler::TakeFirstAsyncGeneratorRequestFromQueue(
     298             :     Node* generator) {
     299             :   // Removes and returns the first AsyncGeneratorRequest from a
     300             :   // JSAsyncGeneratorObject's queue. Asserts that the queue is not empty.
     301             :   CSA_ASSERT(this, TaggedIsAsyncGenerator(generator));
     302             :   Node* request =
     303         112 :       LoadObjectField(generator, JSAsyncGeneratorObject::kQueueOffset);
     304             :   CSA_ASSERT(this, IsNotUndefined(request));
     305             : 
     306             :   Node* next = LoadObjectField(request, AsyncGeneratorRequest::kNextOffset);
     307             : 
     308         112 :   StoreObjectField(generator, JSAsyncGeneratorObject::kQueueOffset, next);
     309         112 :   return request;
     310             : }
     311             : }  // namespace
     312             : 
     313             : // https://tc39.github.io/proposal-async-iteration/
     314             : // Section #sec-asyncgenerator-prototype-next
     315         280 : TF_BUILTIN(AsyncGeneratorPrototypeNext, AsyncGeneratorBuiltinsAssembler) {
     316             :   const int kValueArg = 0;
     317             : 
     318             :   Node* argc =
     319         112 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
     320          56 :   CodeStubArguments args(this, argc);
     321             : 
     322         112 :   Node* generator = args.GetReceiver();
     323         112 :   Node* value = args.GetOptionalArgumentValue(kValueArg);
     324             :   Node* context = Parameter(Descriptor::kContext);
     325             : 
     326          56 :   AsyncGeneratorEnqueue(&args, context, generator, value,
     327             :                         JSAsyncGeneratorObject::kNext,
     328          56 :                         "[AsyncGenerator].prototype.next");
     329          56 : }
     330             : 
     331             : // https://tc39.github.io/proposal-async-iteration/
     332             : // Section #sec-asyncgenerator-prototype-return
     333         280 : TF_BUILTIN(AsyncGeneratorPrototypeReturn, AsyncGeneratorBuiltinsAssembler) {
     334             :   const int kValueArg = 0;
     335             : 
     336             :   Node* argc =
     337         112 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
     338          56 :   CodeStubArguments args(this, argc);
     339             : 
     340         112 :   Node* generator = args.GetReceiver();
     341         112 :   Node* value = args.GetOptionalArgumentValue(kValueArg);
     342             :   Node* context = Parameter(Descriptor::kContext);
     343             : 
     344          56 :   AsyncGeneratorEnqueue(&args, context, generator, value,
     345             :                         JSAsyncGeneratorObject::kReturn,
     346          56 :                         "[AsyncGenerator].prototype.return");
     347          56 : }
     348             : 
     349             : // https://tc39.github.io/proposal-async-iteration/
     350             : // Section #sec-asyncgenerator-prototype-throw
     351         280 : TF_BUILTIN(AsyncGeneratorPrototypeThrow, AsyncGeneratorBuiltinsAssembler) {
     352             :   const int kValueArg = 0;
     353             : 
     354             :   Node* argc =
     355         112 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
     356          56 :   CodeStubArguments args(this, argc);
     357             : 
     358         112 :   Node* generator = args.GetReceiver();
     359         112 :   Node* value = args.GetOptionalArgumentValue(kValueArg);
     360             :   Node* context = Parameter(Descriptor::kContext);
     361             : 
     362          56 :   AsyncGeneratorEnqueue(&args, context, generator, value,
     363             :                         JSAsyncGeneratorObject::kThrow,
     364          56 :                         "[AsyncGenerator].prototype.throw");
     365          56 : }
     366             : 
     367         224 : TF_BUILTIN(AsyncGeneratorAwaitResolveClosure, AsyncGeneratorBuiltinsAssembler) {
     368             :   Node* value = Parameter(Descriptor::kValue);
     369             :   Node* context = Parameter(Descriptor::kContext);
     370          56 :   AsyncGeneratorAwaitResumeClosure(context, value,
     371          56 :                                    JSAsyncGeneratorObject::kNext);
     372          56 : }
     373             : 
     374         224 : TF_BUILTIN(AsyncGeneratorAwaitRejectClosure, AsyncGeneratorBuiltinsAssembler) {
     375             :   Node* value = Parameter(Descriptor::kValue);
     376             :   Node* context = Parameter(Descriptor::kContext);
     377          56 :   AsyncGeneratorAwaitResumeClosure(context, value,
     378          56 :                                    JSAsyncGeneratorObject::kThrow);
     379          56 : }
     380             : 
     381         168 : TF_BUILTIN(AsyncGeneratorAwaitUncaught, AsyncGeneratorBuiltinsAssembler) {
     382             :   const bool kIsCatchable = false;
     383          56 :   AsyncGeneratorAwait<Descriptor>(kIsCatchable);
     384           0 : }
     385             : 
     386         168 : TF_BUILTIN(AsyncGeneratorAwaitCaught, AsyncGeneratorBuiltinsAssembler) {
     387             :   const bool kIsCatchable = true;
     388          56 :   AsyncGeneratorAwait<Descriptor>(kIsCatchable);
     389           0 : }
     390             : 
     391         224 : TF_BUILTIN(AsyncGeneratorResumeNext, AsyncGeneratorBuiltinsAssembler) {
     392             :   typedef AsyncGeneratorResumeNextDescriptor Descriptor;
     393             :   Node* const generator = Parameter(Descriptor::kGenerator);
     394             :   Node* const context = Parameter(Descriptor::kContext);
     395             : 
     396             :   // The penultimate step of proposal-async-iteration/#sec-asyncgeneratorresolve
     397             :   // and proposal-async-iteration/#sec-asyncgeneratorreject both recursively
     398             :   // invoke AsyncGeneratorResumeNext() again.
     399             :   //
     400             :   // This implementation does not implement this recursively, but instead
     401             :   // performs a loop in AsyncGeneratorResumeNext, which  continues as long as
     402             :   // there is an AsyncGeneratorRequest in the queue, and as long as the
     403             :   // generator is not suspended due to an AwaitExpression.
     404         112 :   VARIABLE(var_state, MachineRepresentation::kTaggedSigned,
     405             :            LoadGeneratorState(generator));
     406         112 :   VARIABLE(var_next, MachineRepresentation::kTagged,
     407             :            LoadFirstAsyncGeneratorRequestFromQueue(generator));
     408          56 :   Variable* loop_variables[] = {&var_state, &var_next};
     409         112 :   Label start(this, 2, loop_variables);
     410          56 :   Goto(&start);
     411          56 :   BIND(&start);
     412             : 
     413             :   CSA_ASSERT(this, IsGeneratorNotExecuting(generator));
     414             : 
     415             :   // Stop resuming if suspended for Await.
     416         168 :   ReturnIf(IsGeneratorAwaiting(generator), UndefinedConstant());
     417             : 
     418             :   // Stop resuming if request queue is empty.
     419         224 :   ReturnIf(IsUndefined(var_next.value()), UndefinedConstant());
     420             : 
     421          56 :   Node* const next = var_next.value();
     422             :   TNode<Smi> const resume_type =
     423             :       CAST(LoadResumeTypeFromAsyncGeneratorRequest(next));
     424             : 
     425          56 :   Label if_abrupt(this), if_normal(this), resume_generator(this);
     426         112 :   Branch(IsAbruptResumeType(resume_type), &if_abrupt, &if_normal);
     427          56 :   BIND(&if_abrupt);
     428             :   {
     429          56 :     Label settle_promise(this), if_return(this), if_throw(this);
     430         168 :     GotoIfNot(IsGeneratorStateSuspendedAtStart(var_state.value()),
     431          56 :               &settle_promise);
     432          56 :     CloseGenerator(generator);
     433         112 :     var_state.Bind(SmiConstant(JSGeneratorObject::kGeneratorClosed));
     434          56 :     Goto(&settle_promise);
     435             : 
     436          56 :     BIND(&settle_promise);
     437             :     Node* next_value = LoadValueFromAsyncGeneratorRequest(next);
     438         112 :     Branch(SmiEqual(resume_type, SmiConstant(JSGeneratorObject::kReturn)),
     439          56 :            &if_return, &if_throw);
     440             : 
     441          56 :     BIND(&if_return);
     442             :     // For "return" completions, await the sent value. If the Await succeeds,
     443             :     // and the generator is not closed, resume the generator with a "return"
     444             :     // completion to allow `finally` blocks to be evaluated. Otherwise, perform
     445             :     // AsyncGeneratorResolve(awaitedValue, true). If the await fails and the
     446             :     // generator is not closed, resume the generator with a "throw" completion.
     447             :     // If the generator was closed, perform AsyncGeneratorReject(thrownValue).
     448             :     // In all cases, the last step is to call AsyncGeneratorResumeNext.
     449             :     Node* is_caught = CallRuntime(Runtime::kAsyncGeneratorHasCatchHandlerForPC,
     450             :                                   context, generator);
     451          56 :     TailCallBuiltin(Builtins::kAsyncGeneratorReturn, context, generator,
     452          56 :                     next_value, is_caught);
     453             : 
     454          56 :     BIND(&if_throw);
     455         168 :     GotoIfNot(IsGeneratorStateClosed(var_state.value()), &resume_generator);
     456             :     CallBuiltin(Builtins::kAsyncGeneratorReject, context, generator,
     457          56 :                 next_value);
     458          56 :     var_next.Bind(LoadFirstAsyncGeneratorRequestFromQueue(generator));
     459          56 :     Goto(&start);
     460             :   }
     461             : 
     462          56 :   BIND(&if_normal);
     463             :   {
     464         168 :     GotoIfNot(IsGeneratorStateClosed(var_state.value()), &resume_generator);
     465             :     CallBuiltin(Builtins::kAsyncGeneratorResolve, context, generator,
     466         112 :                 UndefinedConstant(), TrueConstant());
     467          56 :     var_state.Bind(LoadGeneratorState(generator));
     468          56 :     var_next.Bind(LoadFirstAsyncGeneratorRequestFromQueue(generator));
     469          56 :     Goto(&start);
     470             :   }
     471             : 
     472          56 :   BIND(&resume_generator);
     473             :   {
     474             :     // Remember the {resume_type} for the {generator}.
     475             :     StoreObjectFieldNoWriteBarrier(
     476          56 :         generator, JSGeneratorObject::kResumeModeOffset, resume_type);
     477         112 :     CallStub(CodeFactory::ResumeGenerator(isolate()), context,
     478         112 :              LoadValueFromAsyncGeneratorRequest(next), generator);
     479          56 :     var_state.Bind(LoadGeneratorState(generator));
     480          56 :     var_next.Bind(LoadFirstAsyncGeneratorRequestFromQueue(generator));
     481          56 :     Goto(&start);
     482             :   }
     483          56 : }
     484             : 
     485         224 : TF_BUILTIN(AsyncGeneratorResolve, AsyncGeneratorBuiltinsAssembler) {
     486             :   Node* const generator = Parameter(Descriptor::kGenerator);
     487             :   Node* const value = Parameter(Descriptor::kValue);
     488             :   Node* const done = Parameter(Descriptor::kDone);
     489             :   Node* const context = Parameter(Descriptor::kContext);
     490             : 
     491             :   CSA_SLOW_ASSERT(this, TaggedIsAsyncGenerator(generator));
     492             :   CSA_ASSERT(this, Word32BinaryNot(IsGeneratorAwaiting(generator)));
     493             : 
     494             :   // This operation should be called only when the `value` parameter has been
     495             :   // Await-ed. Typically, this means `value` is not a JSPromise value. However,
     496             :   // it may be a JSPromise value whose "then" method has been overridden to a
     497             :   // non-callable value. This can't be checked with assertions due to being
     498             :   // observable, but keep it in mind.
     499             : 
     500          56 :   Node* const next = TakeFirstAsyncGeneratorRequestFromQueue(generator);
     501             :   Node* const promise = LoadPromiseFromAsyncGeneratorRequest(next);
     502             : 
     503             :   // Let iteratorResult be CreateIterResultObject(value, done).
     504         112 :   Node* const iter_result = Allocate(JSIteratorResult::kSize);
     505             :   {
     506         224 :     Node* map = LoadContextElement(LoadNativeContext(context),
     507          56 :                                    Context::ITERATOR_RESULT_MAP_INDEX);
     508          56 :     StoreMapNoWriteBarrier(iter_result, map);
     509             :     StoreObjectFieldRoot(iter_result, JSIteratorResult::kPropertiesOrHashOffset,
     510          56 :                          RootIndex::kEmptyFixedArray);
     511             :     StoreObjectFieldRoot(iter_result, JSIteratorResult::kElementsOffset,
     512          56 :                          RootIndex::kEmptyFixedArray);
     513             :     StoreObjectFieldNoWriteBarrier(iter_result, JSIteratorResult::kValueOffset,
     514          56 :                                    value);
     515             :     StoreObjectFieldNoWriteBarrier(iter_result, JSIteratorResult::kDoneOffset,
     516          56 :                                    done);
     517             :   }
     518             : 
     519             :   // We know that {iter_result} itself doesn't have any "then" property (a
     520             :   // freshly allocated IterResultObject only has "value" and "done" properties)
     521             :   // and we also know that the [[Prototype]] of {iter_result} is the intrinsic
     522             :   // %ObjectPrototype%. So we can skip the [[Resolve]] logic here completely
     523             :   // and directly call into the FulfillPromise operation if we can prove
     524             :   // that the %ObjectPrototype% also doesn't have any "then" property. This
     525             :   // is guarded by the Promise#then() protector.
     526             :   // If the PromiseHooks are enabled, we cannot take the shortcut here, since
     527             :   // the "promiseResolve" hook would not be fired otherwise.
     528          56 :   Label if_fast(this), if_slow(this, Label::kDeferred), return_promise(this);
     529          56 :   GotoIfForceSlowPath(&if_slow);
     530         112 :   GotoIf(IsPromiseHookEnabled(), &if_slow);
     531         112 :   Branch(IsPromiseThenProtectorCellInvalid(), &if_slow, &if_fast);
     532             : 
     533          56 :   BIND(&if_fast);
     534             :   {
     535             :     // Skip the "then" on {iter_result} and directly fulfill the {promise}
     536             :     // with the {iter_result}.
     537          56 :     CallBuiltin(Builtins::kFulfillPromise, context, promise, iter_result);
     538          56 :     Goto(&return_promise);
     539             :   }
     540             : 
     541          56 :   BIND(&if_slow);
     542             :   {
     543             :     // Perform Call(promiseCapability.[[Resolve]], undefined, «iteratorResult»).
     544          56 :     CallBuiltin(Builtins::kResolvePromise, context, promise, iter_result);
     545          56 :     Goto(&return_promise);
     546             :   }
     547             : 
     548             :   // Per spec, AsyncGeneratorResolve() returns undefined. However, for the
     549             :   // benefit of %TraceExit(), return the Promise.
     550          56 :   BIND(&return_promise);
     551          56 :   Return(promise);
     552          56 : }
     553             : 
     554         224 : TF_BUILTIN(AsyncGeneratorReject, AsyncGeneratorBuiltinsAssembler) {
     555             :   typedef AsyncGeneratorRejectDescriptor Descriptor;
     556             :   Node* const generator = Parameter(Descriptor::kGenerator);
     557             :   Node* const value = Parameter(Descriptor::kValue);
     558             :   Node* const context = Parameter(Descriptor::kContext);
     559             : 
     560          56 :   Node* const next = TakeFirstAsyncGeneratorRequestFromQueue(generator);
     561             :   Node* const promise = LoadPromiseFromAsyncGeneratorRequest(next);
     562             : 
     563         112 :   Return(CallBuiltin(Builtins::kRejectPromise, context, promise, value,
     564         168 :                      TrueConstant()));
     565          56 : }
     566             : 
     567         224 : TF_BUILTIN(AsyncGeneratorYield, AsyncGeneratorBuiltinsAssembler) {
     568             :   Node* const generator = Parameter(Descriptor::kGenerator);
     569             :   Node* const value = Parameter(Descriptor::kValue);
     570             :   Node* const is_caught = Parameter(Descriptor::kIsCaught);
     571             :   Node* const context = Parameter(Descriptor::kContext);
     572             : 
     573             :   Node* const request = LoadFirstAsyncGeneratorRequestFromQueue(generator);
     574             :   Node* const outer_promise = LoadPromiseFromAsyncGeneratorRequest(request);
     575             : 
     576             :   const int on_resolve = Context::ASYNC_GENERATOR_YIELD_RESOLVE_SHARED_FUN;
     577             :   const int on_reject = Context::ASYNC_GENERATOR_AWAIT_REJECT_SHARED_FUN;
     578             : 
     579          56 :   SetGeneratorAwaiting(generator);
     580          56 :   Await(context, generator, value, outer_promise, on_resolve, on_reject,
     581          56 :         is_caught);
     582         112 :   Return(UndefinedConstant());
     583          56 : }
     584             : 
     585         224 : TF_BUILTIN(AsyncGeneratorYieldResolveClosure, AsyncGeneratorBuiltinsAssembler) {
     586             :   Node* const context = Parameter(Descriptor::kContext);
     587             :   Node* const value = Parameter(Descriptor::kValue);
     588         112 :   Node* const generator = LoadContextElement(context, Context::EXTENSION_INDEX);
     589             : 
     590          56 :   SetGeneratorNotAwaiting(generator);
     591             : 
     592             :   // Per proposal-async-iteration/#sec-asyncgeneratoryield step 9
     593             :   // Return ! AsyncGeneratorResolve(_F_.[[Generator]], _value_, *false*).
     594             :   CallBuiltin(Builtins::kAsyncGeneratorResolve, context, generator, value,
     595         112 :               FalseConstant());
     596             : 
     597          56 :   TailCallBuiltin(Builtins::kAsyncGeneratorResumeNext, context, generator);
     598          56 : }
     599             : 
     600         280 : TF_BUILTIN(AsyncGeneratorReturn, AsyncGeneratorBuiltinsAssembler) {
     601             :   // AsyncGeneratorReturn is called when resuming requests with "return" resume
     602             :   // modes. It is similar to AsyncGeneratorAwait(), but selects different
     603             :   // resolve/reject closures depending on whether or not the generator is marked
     604             :   // as closed.
     605             :   //
     606             :   // In particular, non-closed generators will resume the generator with either
     607             :   // "return" or "throw" resume modes, allowing finally blocks or catch blocks
     608             :   // to be evaluated, as if the `await` were performed within the body of the
     609             :   // generator. (per proposal-async-iteration/#sec-asyncgeneratoryield step 8.b)
     610             :   //
     611             :   // Closed generators do not resume the generator in the resolve/reject
     612             :   // closures, but instead simply perform AsyncGeneratorResolve or
     613             :   // AsyncGeneratorReject with the awaited value
     614             :   // (per proposal-async-iteration/#sec-asyncgeneratorresumenext step 10.b.i)
     615             :   //
     616             :   // In all cases, the final step is to jump back to AsyncGeneratorResumeNext.
     617             :   Node* const generator = Parameter(Descriptor::kGenerator);
     618             :   Node* const value = Parameter(Descriptor::kValue);
     619             :   Node* const is_caught = Parameter(Descriptor::kIsCaught);
     620             :   Node* const req = LoadFirstAsyncGeneratorRequestFromQueue(generator);
     621             :   CSA_ASSERT(this, IsNotUndefined(req));
     622             : 
     623          56 :   Label perform_await(this);
     624         168 :   VARIABLE(var_on_resolve, MachineType::PointerRepresentation(),
     625             :            IntPtrConstant(
     626             :                Context::ASYNC_GENERATOR_RETURN_CLOSED_RESOLVE_SHARED_FUN));
     627         168 :   VARIABLE(
     628             :       var_on_reject, MachineType::PointerRepresentation(),
     629             :       IntPtrConstant(Context::ASYNC_GENERATOR_RETURN_CLOSED_REJECT_SHARED_FUN));
     630             : 
     631             :   Node* const state = LoadGeneratorState(generator);
     632         112 :   GotoIf(IsGeneratorStateClosed(state), &perform_await);
     633             :   var_on_resolve.Bind(
     634         112 :       IntPtrConstant(Context::ASYNC_GENERATOR_RETURN_RESOLVE_SHARED_FUN));
     635             :   var_on_reject.Bind(
     636         112 :       IntPtrConstant(Context::ASYNC_GENERATOR_AWAIT_REJECT_SHARED_FUN));
     637          56 :   Goto(&perform_await);
     638             : 
     639          56 :   BIND(&perform_await);
     640             : 
     641          56 :   SetGeneratorAwaiting(generator);
     642             :   Node* const context = Parameter(Descriptor::kContext);
     643             :   Node* const outer_promise = LoadPromiseFromAsyncGeneratorRequest(req);
     644          56 :   Await(context, generator, value, outer_promise, var_on_resolve.value(),
     645          56 :         var_on_reject.value(), is_caught);
     646             : 
     647         112 :   Return(UndefinedConstant());
     648          56 : }
     649             : 
     650             : // On-resolve closure for Await in AsyncGeneratorReturn
     651             : // Resume the generator with "return" resume_mode, and finally perform
     652             : // AsyncGeneratorResumeNext. Per
     653             : // proposal-async-iteration/#sec-asyncgeneratoryield step 8.e
     654         224 : TF_BUILTIN(AsyncGeneratorReturnResolveClosure,
     655             :            AsyncGeneratorBuiltinsAssembler) {
     656             :   Node* const context = Parameter(Descriptor::kContext);
     657             :   Node* const value = Parameter(Descriptor::kValue);
     658          56 :   AsyncGeneratorAwaitResumeClosure(context, value, JSGeneratorObject::kReturn);
     659          56 : }
     660             : 
     661             : // On-resolve closure for Await in AsyncGeneratorReturn
     662             : // Perform AsyncGeneratorResolve({awaited_value}, true) and finally perform
     663             : // AsyncGeneratorResumeNext.
     664         224 : TF_BUILTIN(AsyncGeneratorReturnClosedResolveClosure,
     665             :            AsyncGeneratorBuiltinsAssembler) {
     666             :   Node* const context = Parameter(Descriptor::kContext);
     667             :   Node* const value = Parameter(Descriptor::kValue);
     668         112 :   Node* const generator = LoadContextElement(context, Context::EXTENSION_INDEX);
     669             : 
     670          56 :   SetGeneratorNotAwaiting(generator);
     671             : 
     672             :   // https://tc39.github.io/proposal-async-iteration/
     673             :   //    #async-generator-resume-next-return-processor-fulfilled step 2:
     674             :   //  Return ! AsyncGeneratorResolve(_F_.[[Generator]], _value_, *true*).
     675             :   CallBuiltin(Builtins::kAsyncGeneratorResolve, context, generator, value,
     676         112 :               TrueConstant());
     677             : 
     678          56 :   TailCallBuiltin(Builtins::kAsyncGeneratorResumeNext, context, generator);
     679          56 : }
     680             : 
     681         224 : TF_BUILTIN(AsyncGeneratorReturnClosedRejectClosure,
     682             :            AsyncGeneratorBuiltinsAssembler) {
     683             :   Node* const context = Parameter(Descriptor::kContext);
     684             :   Node* const value = Parameter(Descriptor::kValue);
     685         112 :   Node* const generator = LoadContextElement(context, Context::EXTENSION_INDEX);
     686             : 
     687          56 :   SetGeneratorNotAwaiting(generator);
     688             : 
     689             :   // https://tc39.github.io/proposal-async-iteration/
     690             :   //    #async-generator-resume-next-return-processor-rejected step 2:
     691             :   // Return ! AsyncGeneratorReject(_F_.[[Generator]], _reason_).
     692          56 :   CallBuiltin(Builtins::kAsyncGeneratorReject, context, generator, value);
     693             : 
     694          56 :   TailCallBuiltin(Builtins::kAsyncGeneratorResumeNext, context, generator);
     695          56 : }
     696             : 
     697             : }  // namespace internal
     698       59456 : }  // namespace v8

Generated by: LCOV version 1.10