LCOV - code coverage report
Current view: top level - src/builtins - builtins-async-function-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 41 41 100.0 %
Date: 2017-10-20 Functions: 15 15 100.0 %

          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-stub-assembler.h"
       9             : #include "src/objects-inl.h"
      10             : 
      11             : namespace v8 {
      12             : namespace internal {
      13             : 
      14             : class AsyncFunctionBuiltinsAssembler : public AsyncBuiltinsAssembler {
      15             :  public:
      16             :   explicit AsyncFunctionBuiltinsAssembler(compiler::CodeAssemblerState* state)
      17             :       : AsyncBuiltinsAssembler(state) {}
      18             : 
      19             :  protected:
      20             :   void AsyncFunctionAwait(Node* const context, Node* const generator,
      21             :                           Node* const awaited, Node* const outer_promise,
      22             :                           const bool is_predicted_as_caught);
      23             : 
      24             :   void AsyncFunctionAwaitResumeClosure(
      25             :       Node* const context, Node* const sent_value,
      26             :       JSGeneratorObject::ResumeMode resume_mode);
      27             : };
      28             : 
      29             : namespace {
      30             : 
      31             : // Describe fields of Context associated with AsyncFunctionAwait resume
      32             : // closures.
      33             : // TODO(jgruber): Refactor to reuse code for upcoming async-generators.
      34             : class AwaitContext {
      35             :  public:
      36             :   enum Fields { kGeneratorSlot = Context::MIN_CONTEXT_SLOTS, kLength };
      37             : };
      38             : 
      39             : }  // anonymous namespace
      40             : 
      41          62 : void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwaitResumeClosure(
      42             :     Node* context, Node* sent_value,
      43             :     JSGeneratorObject::ResumeMode resume_mode) {
      44             :   DCHECK(resume_mode == JSGeneratorObject::kNext ||
      45             :          resume_mode == JSGeneratorObject::kThrow);
      46             : 
      47             :   Node* const generator =
      48         124 :       LoadContextElement(context, AwaitContext::kGeneratorSlot);
      49             :   CSA_SLOW_ASSERT(this, HasInstanceType(generator, JS_GENERATOR_OBJECT_TYPE));
      50             : 
      51             :   // Inline version of GeneratorPrototypeNext / GeneratorPrototypeReturn with
      52             :   // unnecessary runtime checks removed.
      53             :   // TODO(jgruber): Refactor to reuse code from builtins-generator.cc.
      54             : 
      55             :   // Ensure that the generator is neither closed nor running.
      56             :   CSA_SLOW_ASSERT(
      57             :       this,
      58             :       SmiGreaterThan(
      59             :           LoadObjectField(generator, JSGeneratorObject::kContinuationOffset),
      60             :           SmiConstant(JSGeneratorObject::kGeneratorClosed)));
      61             : 
      62             :   // Resume the {receiver} using our trampoline.
      63          62 :   Callable callable = CodeFactory::ResumeGenerator(isolate());
      64          62 :   CallStub(callable, context, sent_value, generator, SmiConstant(resume_mode));
      65             : 
      66             :   // The resulting Promise is a throwaway, so it doesn't matter what it
      67             :   // resolves to. What is important is that we don't end up keeping the
      68             :   // whole chain of intermediate Promises alive by returning the return value
      69             :   // of ResumeGenerator, as that would create a memory leak.
      70          62 : }
      71             : 
      72         124 : TF_BUILTIN(AsyncFunctionAwaitRejectClosure, AsyncFunctionBuiltinsAssembler) {
      73             :   CSA_ASSERT_JS_ARGC_EQ(this, 1);
      74             :   Node* const sentError = Parameter(Descriptor::kSentError);
      75             :   Node* const context = Parameter(Descriptor::kContext);
      76             : 
      77             :   AsyncFunctionAwaitResumeClosure(context, sentError,
      78          31 :                                   JSGeneratorObject::kThrow);
      79          62 :   Return(UndefinedConstant());
      80          31 : }
      81             : 
      82         124 : TF_BUILTIN(AsyncFunctionAwaitResolveClosure, AsyncFunctionBuiltinsAssembler) {
      83             :   CSA_ASSERT_JS_ARGC_EQ(this, 1);
      84             :   Node* const sentValue = Parameter(Descriptor::kSentValue);
      85             :   Node* const context = Parameter(Descriptor::kContext);
      86             : 
      87          31 :   AsyncFunctionAwaitResumeClosure(context, sentValue, JSGeneratorObject::kNext);
      88          62 :   Return(UndefinedConstant());
      89          31 : }
      90             : 
      91             : // ES#abstract-ops-async-function-await
      92             : // AsyncFunctionAwait ( value )
      93             : // Shared logic for the core of await. The parser desugars
      94             : //   await awaited
      95             : // into
      96             : //   yield AsyncFunctionAwait{Caught,Uncaught}(.generator, awaited, .promise)
      97             : // The 'awaited' parameter is the value; the generator stands in
      98             : // for the asyncContext, and .promise is the larger promise under
      99             : // construction by the enclosing async function.
     100          62 : void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait(
     101             :     Node* const context, Node* const generator, Node* const awaited,
     102             :     Node* const outer_promise, const bool is_predicted_as_caught) {
     103             :   CSA_SLOW_ASSERT(this, HasInstanceType(generator, JS_GENERATOR_OBJECT_TYPE));
     104             :   CSA_SLOW_ASSERT(this, HasInstanceType(outer_promise, JS_PROMISE_TYPE));
     105             : 
     106          62 :   ContextInitializer init_closure_context = [&](Node* context) {
     107             :     StoreContextElementNoWriteBarrier(context, AwaitContext::kGeneratorSlot,
     108         124 :                                       generator);
     109          62 :   };
     110             : 
     111             :   // TODO(jgruber): AsyncBuiltinsAssembler::Await currently does not reuse
     112             :   // the awaited promise if it is already a promise. Reuse is non-spec compliant
     113             :   // but part of our old behavior gives us a couple of percent
     114             :   // performance boost.
     115             :   // TODO(jgruber): Use a faster specialized version of
     116             :   // InternalPerformPromiseThen.
     117             : 
     118             :   Await(context, generator, awaited, outer_promise, AwaitContext::kLength,
     119             :         init_closure_context, Context::ASYNC_FUNCTION_AWAIT_RESOLVE_SHARED_FUN,
     120             :         Context::ASYNC_FUNCTION_AWAIT_REJECT_SHARED_FUN,
     121          62 :         is_predicted_as_caught);
     122             : 
     123             :   // Return outer promise to avoid adding an load of the outer promise before
     124             :   // suspending in BytecodeGenerator.
     125          62 :   Return(outer_promise);
     126          62 : }
     127             : 
     128             : // Called by the parser from the desugaring of 'await' when catch
     129             : // prediction indicates that there is a locally surrounding catch block.
     130         124 : TF_BUILTIN(AsyncFunctionAwaitCaught, AsyncFunctionBuiltinsAssembler) {
     131             :   CSA_ASSERT_JS_ARGC_EQ(this, 3);
     132             :   Node* const generator = Parameter(Descriptor::kGenerator);
     133             :   Node* const awaited = Parameter(Descriptor::kAwaited);
     134             :   Node* const outer_promise = Parameter(Descriptor::kOuterPromise);
     135             :   Node* const context = Parameter(Descriptor::kContext);
     136             : 
     137             :   static const bool kIsPredictedAsCaught = true;
     138             : 
     139             :   AsyncFunctionAwait(context, generator, awaited, outer_promise,
     140          31 :                      kIsPredictedAsCaught);
     141          31 : }
     142             : 
     143             : // Called by the parser from the desugaring of 'await' when catch
     144             : // prediction indicates no locally surrounding catch block.
     145         124 : TF_BUILTIN(AsyncFunctionAwaitUncaught, AsyncFunctionBuiltinsAssembler) {
     146             :   CSA_ASSERT_JS_ARGC_EQ(this, 3);
     147             :   Node* const generator = Parameter(Descriptor::kGenerator);
     148             :   Node* const awaited = Parameter(Descriptor::kAwaited);
     149             :   Node* const outer_promise = Parameter(Descriptor::kOuterPromise);
     150             :   Node* const context = Parameter(Descriptor::kContext);
     151             : 
     152             :   static const bool kIsPredictedAsCaught = false;
     153             : 
     154             :   AsyncFunctionAwait(context, generator, awaited, outer_promise,
     155          31 :                      kIsPredictedAsCaught);
     156          31 : }
     157             : 
     158         124 : TF_BUILTIN(AsyncFunctionPromiseCreate, AsyncFunctionBuiltinsAssembler) {
     159             :   CSA_ASSERT_JS_ARGC_EQ(this, 0);
     160             :   Node* const context = Parameter(Descriptor::kContext);
     161             : 
     162          31 :   Node* const promise = AllocateAndInitJSPromise(context);
     163             : 
     164             :   Label if_is_debug_active(this, Label::kDeferred);
     165          62 :   GotoIf(IsDebugActive(), &if_is_debug_active);
     166             : 
     167             :   // Early exit if debug is not active.
     168          31 :   Return(promise);
     169             : 
     170          31 :   BIND(&if_is_debug_active);
     171             :   {
     172             :     // Push the Promise under construction in an async function on
     173             :     // the catch prediction stack to handle exceptions thrown before
     174             :     // the first await.
     175             :     // Assign ID and create a recurring task to save stack for future
     176             :     // resumptions from await.
     177             :     CallRuntime(Runtime::kDebugAsyncFunctionPromiseCreated, context, promise);
     178          31 :     Return(promise);
     179          31 :   }
     180          31 : }
     181             : 
     182         124 : TF_BUILTIN(AsyncFunctionPromiseRelease, AsyncFunctionBuiltinsAssembler) {
     183             :   CSA_ASSERT_JS_ARGC_EQ(this, 1);
     184             :   Node* const promise = Parameter(Descriptor::kPromise);
     185             :   Node* const context = Parameter(Descriptor::kContext);
     186             : 
     187             :   Label if_is_debug_active(this, Label::kDeferred);
     188          62 :   GotoIf(IsDebugActive(), &if_is_debug_active);
     189             : 
     190             :   // Early exit if debug is not active.
     191          62 :   Return(UndefinedConstant());
     192             : 
     193          31 :   BIND(&if_is_debug_active);
     194             :   {
     195             :     // Pop the Promise under construction in an async function on
     196             :     // from catch prediction stack.
     197             :     CallRuntime(Runtime::kDebugPopPromise, context);
     198          31 :     Return(promise);
     199          31 :   }
     200          31 : }
     201             : 
     202             : }  // namespace internal
     203             : }  // namespace v8

Generated by: LCOV version 1.10