LCOV - code coverage report
Current view: top level - src/builtins - builtins-async-generator-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 225 227 99.1 %
Date: 2017-10-20 Functions: 47 49 95.9 %

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

Generated by: LCOV version 1.10