LCOV - code coverage report
Current view: top level - src/builtins - builtins-async-function-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 44 44 100.0 %
Date: 2017-04-26 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          86 : 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          86 :       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          86 :   Callable callable = CodeFactory::ResumeGenerator(isolate());
      64             :   CallStub(callable, context, sent_value, generator, SmiConstant(resume_mode),
      65          86 :            SmiConstant(static_cast<int>(SuspendFlags::kGeneratorAwait)));
      66             : 
      67             :   // The resulting Promise is a throwaway, so it doesn't matter what it
      68             :   // resolves to. What is important is that we don't end up keeping the
      69             :   // whole chain of intermediate Promises alive by returning the return value
      70             :   // of ResumeGenerator, as that would create a memory leak.
      71          86 : }
      72             : 
      73         172 : TF_BUILTIN(AsyncFunctionAwaitRejectClosure, AsyncFunctionBuiltinsAssembler) {
      74             :   CSA_ASSERT_JS_ARGC_EQ(this, 1);
      75             :   Node* const sentError = Parameter(Descriptor::kSentError);
      76             :   Node* const context = Parameter(Descriptor::kContext);
      77             : 
      78             :   AsyncFunctionAwaitResumeClosure(context, sentError,
      79          43 :                                   JSGeneratorObject::kThrow);
      80          43 :   Return(UndefinedConstant());
      81          43 : }
      82             : 
      83         172 : TF_BUILTIN(AsyncFunctionAwaitResolveClosure, AsyncFunctionBuiltinsAssembler) {
      84             :   CSA_ASSERT_JS_ARGC_EQ(this, 1);
      85             :   Node* const sentValue = Parameter(Descriptor::kSentValue);
      86             :   Node* const context = Parameter(Descriptor::kContext);
      87             : 
      88          43 :   AsyncFunctionAwaitResumeClosure(context, sentValue, JSGeneratorObject::kNext);
      89          43 :   Return(UndefinedConstant());
      90          43 : }
      91             : 
      92             : // ES#abstract-ops-async-function-await
      93             : // AsyncFunctionAwait ( value )
      94             : // Shared logic for the core of await. The parser desugars
      95             : //   await awaited
      96             : // into
      97             : //   yield AsyncFunctionAwait{Caught,Uncaught}(.generator, awaited, .promise)
      98             : // The 'awaited' parameter is the value; the generator stands in
      99             : // for the asyncContext, and .promise is the larger promise under
     100             : // construction by the enclosing async function.
     101          86 : void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait(
     102             :     Node* const context, Node* const generator, Node* const awaited,
     103             :     Node* const outer_promise, const bool is_predicted_as_caught) {
     104             :   CSA_SLOW_ASSERT(this, HasInstanceType(generator, JS_GENERATOR_OBJECT_TYPE));
     105             :   CSA_SLOW_ASSERT(this, HasInstanceType(outer_promise, JS_PROMISE_TYPE));
     106             : 
     107          86 :   NodeGenerator1 create_closure_context = [&](Node* native_context) -> Node* {
     108             :     Node* const context =
     109          86 :         CreatePromiseContext(native_context, AwaitContext::kLength);
     110             :     StoreContextElementNoWriteBarrier(context, AwaitContext::kGeneratorSlot,
     111          86 :                                       generator);
     112          86 :     return context;
     113             :   };
     114             : 
     115             :   // TODO(jgruber): AsyncBuiltinsAssembler::Await currently does not reuse
     116             :   // the awaited promise if it is already a promise. Reuse is non-spec compliant
     117             :   // but part of our old behavior gives us a couple of percent
     118             :   // performance boost.
     119             :   // TODO(jgruber): Use a faster specialized version of
     120             :   // InternalPerformPromiseThen.
     121             : 
     122             :   Node* const result = Await(
     123             :       context, generator, awaited, outer_promise, create_closure_context,
     124             :       Context::ASYNC_FUNCTION_AWAIT_RESOLVE_SHARED_FUN,
     125          86 :       Context::ASYNC_FUNCTION_AWAIT_REJECT_SHARED_FUN, is_predicted_as_caught);
     126             : 
     127          86 :   Return(result);
     128          86 : }
     129             : 
     130             : // Called by the parser from the desugaring of 'await' when catch
     131             : // prediction indicates that there is a locally surrounding catch block.
     132         172 : TF_BUILTIN(AsyncFunctionAwaitCaught, AsyncFunctionBuiltinsAssembler) {
     133             :   CSA_ASSERT_JS_ARGC_EQ(this, 3);
     134             :   Node* const generator = Parameter(Descriptor::kGenerator);
     135             :   Node* const awaited = Parameter(Descriptor::kAwaited);
     136             :   Node* const outer_promise = Parameter(Descriptor::kOuterPromise);
     137             :   Node* const context = Parameter(Descriptor::kContext);
     138             : 
     139             :   static const bool kIsPredictedAsCaught = true;
     140             : 
     141             :   AsyncFunctionAwait(context, generator, awaited, outer_promise,
     142          43 :                      kIsPredictedAsCaught);
     143          43 : }
     144             : 
     145             : // Called by the parser from the desugaring of 'await' when catch
     146             : // prediction indicates no locally surrounding catch block.
     147         172 : TF_BUILTIN(AsyncFunctionAwaitUncaught, AsyncFunctionBuiltinsAssembler) {
     148             :   CSA_ASSERT_JS_ARGC_EQ(this, 3);
     149             :   Node* const generator = Parameter(Descriptor::kGenerator);
     150             :   Node* const awaited = Parameter(Descriptor::kAwaited);
     151             :   Node* const outer_promise = Parameter(Descriptor::kOuterPromise);
     152             :   Node* const context = Parameter(Descriptor::kContext);
     153             : 
     154             :   static const bool kIsPredictedAsCaught = false;
     155             : 
     156             :   AsyncFunctionAwait(context, generator, awaited, outer_promise,
     157          43 :                      kIsPredictedAsCaught);
     158          43 : }
     159             : 
     160         172 : TF_BUILTIN(AsyncFunctionPromiseCreate, AsyncFunctionBuiltinsAssembler) {
     161             :   CSA_ASSERT_JS_ARGC_EQ(this, 0);
     162             :   Node* const context = Parameter(Descriptor::kContext);
     163             : 
     164          43 :   Node* const promise = AllocateAndInitJSPromise(context);
     165             : 
     166             :   Label if_is_debug_active(this, Label::kDeferred);
     167          43 :   GotoIf(IsDebugActive(), &if_is_debug_active);
     168             : 
     169             :   // Early exit if debug is not active.
     170          43 :   Return(promise);
     171             : 
     172          43 :   BIND(&if_is_debug_active);
     173             :   {
     174             :     // Push the Promise under construction in an async function on
     175             :     // the catch prediction stack to handle exceptions thrown before
     176             :     // the first await.
     177             :     // Assign ID and create a recurring task to save stack for future
     178             :     // resumptions from await.
     179          43 :     CallRuntime(Runtime::kDebugAsyncFunctionPromiseCreated, context, promise);
     180          43 :     Return(promise);
     181          43 :   }
     182          43 : }
     183             : 
     184         172 : TF_BUILTIN(AsyncFunctionPromiseRelease, AsyncFunctionBuiltinsAssembler) {
     185             :   CSA_ASSERT_JS_ARGC_EQ(this, 1);
     186             :   Node* const promise = Parameter(Descriptor::kPromise);
     187             :   Node* const context = Parameter(Descriptor::kContext);
     188             : 
     189             :   Label if_is_debug_active(this, Label::kDeferred);
     190          43 :   GotoIf(IsDebugActive(), &if_is_debug_active);
     191             : 
     192             :   // Early exit if debug is not active.
     193          43 :   Return(UndefinedConstant());
     194             : 
     195          43 :   BIND(&if_is_debug_active);
     196             :   {
     197             :     // Pop the Promise under construction in an async function on
     198             :     // from catch prediction stack.
     199          43 :     CallRuntime(Runtime::kDebugPopPromise, context);
     200          43 :     Return(promise);
     201          43 :   }
     202          43 : }
     203             : 
     204             : }  // namespace internal
     205             : }  // namespace v8

Generated by: LCOV version 1.10