LCOV - code coverage report
Current view: top level - src/builtins - builtins-async-function-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 98 100 98.0 %
Date: 2019-04-17 Functions: 18 20 90.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             : #include "src/objects/js-generator.h"
      11             : #include "src/objects/js-promise.h"
      12             : 
      13             : namespace v8 {
      14             : namespace internal {
      15             : 
      16         448 : class AsyncFunctionBuiltinsAssembler : public AsyncBuiltinsAssembler {
      17             :  public:
      18             :   explicit AsyncFunctionBuiltinsAssembler(compiler::CodeAssemblerState* state)
      19             :       : AsyncBuiltinsAssembler(state) {}
      20             : 
      21             :  protected:
      22             :   template <typename Descriptor>
      23             :   void AsyncFunctionAwait(const bool is_predicted_as_caught);
      24             : 
      25             :   void AsyncFunctionAwaitResumeClosure(
      26             :       Node* const context, Node* const sent_value,
      27             :       JSGeneratorObject::ResumeMode resume_mode);
      28             : };
      29             : 
      30         112 : void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwaitResumeClosure(
      31             :     Node* context, Node* sent_value,
      32             :     JSGeneratorObject::ResumeMode resume_mode) {
      33             :   DCHECK(resume_mode == JSGeneratorObject::kNext ||
      34             :          resume_mode == JSGeneratorObject::kThrow);
      35             : 
      36             :   TNode<JSAsyncFunctionObject> async_function_object =
      37         112 :       CAST(LoadContextElement(context, Context::EXTENSION_INDEX));
      38             : 
      39             :   // Inline version of GeneratorPrototypeNext / GeneratorPrototypeReturn with
      40             :   // unnecessary runtime checks removed.
      41             : 
      42             :   // Ensure that the {async_function_object} is neither closed nor running.
      43             :   CSA_SLOW_ASSERT(
      44             :       this, SmiGreaterThan(
      45             :                 LoadObjectField<Smi>(async_function_object,
      46             :                                      JSGeneratorObject::kContinuationOffset),
      47             :                 SmiConstant(JSGeneratorObject::kGeneratorClosed)));
      48             : 
      49             :   // Remember the {resume_mode} for the {async_function_object}.
      50         112 :   StoreObjectFieldNoWriteBarrier(async_function_object,
      51             :                                  JSGeneratorObject::kResumeModeOffset,
      52             :                                  SmiConstant(resume_mode));
      53             : 
      54             :   // Resume the {receiver} using our trampoline.
      55         112 :   Callable callable = CodeFactory::ResumeGenerator(isolate());
      56         112 :   CallStub(callable, context, sent_value, async_function_object);
      57             : 
      58             :   // The resulting Promise is a throwaway, so it doesn't matter what it
      59             :   // resolves to. What is important is that we don't end up keeping the
      60             :   // whole chain of intermediate Promises alive by returning the return value
      61             :   // of ResumeGenerator, as that would create a memory leak.
      62         112 : }
      63             : 
      64         224 : TF_BUILTIN(AsyncFunctionEnter, AsyncFunctionBuiltinsAssembler) {
      65             :   TNode<JSFunction> closure = CAST(Parameter(Descriptor::kClosure));
      66             :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
      67             :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
      68             : 
      69             :   // Compute the number of registers and parameters.
      70             :   TNode<SharedFunctionInfo> shared = LoadObjectField<SharedFunctionInfo>(
      71          56 :       closure, JSFunction::kSharedFunctionInfoOffset);
      72             :   TNode<IntPtrT> formal_parameter_count = ChangeInt32ToIntPtr(
      73             :       LoadObjectField(shared, SharedFunctionInfo::kFormalParameterCountOffset,
      74         112 :                       MachineType::Uint16()));
      75             :   TNode<BytecodeArray> bytecode_array =
      76          56 :       LoadSharedFunctionInfoBytecodeArray(shared);
      77             :   TNode<IntPtrT> frame_size = ChangeInt32ToIntPtr(LoadObjectField(
      78         112 :       bytecode_array, BytecodeArray::kFrameSizeOffset, MachineType::Int32()));
      79             :   TNode<IntPtrT> parameters_and_register_length =
      80         112 :       Signed(IntPtrAdd(WordSar(frame_size, IntPtrConstant(kTaggedSizeLog2)),
      81             :                        formal_parameter_count));
      82             : 
      83             :   // Allocate space for the promise, the async function object
      84             :   // and the register file.
      85             :   TNode<IntPtrT> size = IntPtrAdd(
      86             :       IntPtrConstant(JSPromise::kSizeWithEmbedderFields +
      87             :                      JSAsyncFunctionObject::kSize + FixedArray::kHeaderSize),
      88             :       Signed(WordShl(parameters_and_register_length,
      89         168 :                      IntPtrConstant(kTaggedSizeLog2))));
      90          56 :   TNode<HeapObject> base = AllocateInNewSpace(size);
      91             : 
      92             :   // Initialize the register file.
      93             :   TNode<FixedArray> parameters_and_registers = UncheckedCast<FixedArray>(
      94             :       InnerAllocate(base, JSAsyncFunctionObject::kSize +
      95          56 :                               JSPromise::kSizeWithEmbedderFields));
      96          56 :   StoreMapNoWriteBarrier(parameters_and_registers, RootIndex::kFixedArrayMap);
      97             :   StoreObjectFieldNoWriteBarrier(parameters_and_registers,
      98             :                                  FixedArray::kLengthOffset,
      99             :                                  SmiFromIntPtr(parameters_and_register_length));
     100             :   FillFixedArrayWithValue(HOLEY_ELEMENTS, parameters_and_registers,
     101         112 :                           IntPtrConstant(0), parameters_and_register_length,
     102          56 :                           RootIndex::kUndefinedValue);
     103             : 
     104             :   // Initialize the promise.
     105          56 :   TNode<Context> native_context = LoadNativeContext(context);
     106             :   TNode<JSFunction> promise_function =
     107          56 :       CAST(LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX));
     108             :   TNode<Map> promise_map = LoadObjectField<Map>(
     109             :       promise_function, JSFunction::kPrototypeOrInitialMapOffset);
     110             :   TNode<JSPromise> promise = UncheckedCast<JSPromise>(
     111          56 :       InnerAllocate(base, JSAsyncFunctionObject::kSize));
     112          56 :   StoreMapNoWriteBarrier(promise, promise_map);
     113             :   StoreObjectFieldRoot(promise, JSPromise::kPropertiesOrHashOffset,
     114          56 :                        RootIndex::kEmptyFixedArray);
     115             :   StoreObjectFieldRoot(promise, JSPromise::kElementsOffset,
     116          56 :                        RootIndex::kEmptyFixedArray);
     117          56 :   PromiseInit(promise);
     118             : 
     119             :   // Initialize the async function object.
     120          56 :   TNode<Map> async_function_object_map = CAST(LoadContextElement(
     121             :       native_context, Context::ASYNC_FUNCTION_OBJECT_MAP_INDEX));
     122             :   TNode<JSAsyncFunctionObject> async_function_object =
     123             :       UncheckedCast<JSAsyncFunctionObject>(base);
     124          56 :   StoreMapNoWriteBarrier(async_function_object, async_function_object_map);
     125             :   StoreObjectFieldRoot(async_function_object,
     126             :                        JSAsyncFunctionObject::kPropertiesOrHashOffset,
     127          56 :                        RootIndex::kEmptyFixedArray);
     128             :   StoreObjectFieldRoot(async_function_object,
     129             :                        JSAsyncFunctionObject::kElementsOffset,
     130          56 :                        RootIndex::kEmptyFixedArray);
     131             :   StoreObjectFieldNoWriteBarrier(
     132             :       async_function_object, JSAsyncFunctionObject::kFunctionOffset, closure);
     133             :   StoreObjectFieldNoWriteBarrier(
     134             :       async_function_object, JSAsyncFunctionObject::kContextOffset, context);
     135             :   StoreObjectFieldNoWriteBarrier(
     136             :       async_function_object, JSAsyncFunctionObject::kReceiverOffset, receiver);
     137          56 :   StoreObjectFieldNoWriteBarrier(async_function_object,
     138             :                                  JSAsyncFunctionObject::kInputOrDebugPosOffset,
     139             :                                  SmiConstant(0));
     140             :   StoreObjectFieldNoWriteBarrier(async_function_object,
     141             :                                  JSAsyncFunctionObject::kResumeModeOffset,
     142             :                                  SmiConstant(JSAsyncFunctionObject::kNext));
     143          56 :   StoreObjectFieldNoWriteBarrier(
     144             :       async_function_object, JSAsyncFunctionObject::kContinuationOffset,
     145             :       SmiConstant(JSAsyncFunctionObject::kGeneratorExecuting));
     146             :   StoreObjectFieldNoWriteBarrier(
     147             :       async_function_object,
     148             :       JSAsyncFunctionObject::kParametersAndRegistersOffset,
     149             :       parameters_and_registers);
     150             :   StoreObjectFieldNoWriteBarrier(
     151             :       async_function_object, JSAsyncFunctionObject::kPromiseOffset, promise);
     152             : 
     153             :   // Fire promise hooks if enabled and push the Promise under construction
     154             :   // in an async function on the catch prediction stack to handle exceptions
     155             :   // thrown before the first await.
     156          56 :   Label if_instrumentation(this, Label::kDeferred),
     157          56 :       if_instrumentation_done(this);
     158         112 :   Branch(IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(),
     159          56 :          &if_instrumentation, &if_instrumentation_done);
     160          56 :   BIND(&if_instrumentation);
     161             :   {
     162             :     CallRuntime(Runtime::kDebugAsyncFunctionEntered, context, promise);
     163          56 :     Goto(&if_instrumentation_done);
     164             :   }
     165          56 :   BIND(&if_instrumentation_done);
     166             : 
     167          56 :   Return(async_function_object);
     168          56 : }
     169             : 
     170         336 : TF_BUILTIN(AsyncFunctionReject, AsyncFunctionBuiltinsAssembler) {
     171             :   TNode<JSAsyncFunctionObject> async_function_object =
     172             :       CAST(Parameter(Descriptor::kAsyncFunctionObject));
     173          56 :   TNode<Object> reason = CAST(Parameter(Descriptor::kReason));
     174          56 :   TNode<Oddball> can_suspend = CAST(Parameter(Descriptor::kCanSuspend));
     175             :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     176             :   TNode<JSPromise> promise = LoadObjectField<JSPromise>(
     177          56 :       async_function_object, JSAsyncFunctionObject::kPromiseOffset);
     178             : 
     179             :   // Reject the {promise} for the given {reason}, disabling the
     180             :   // additional debug event for the rejection since a debug event
     181             :   // already happend for the exception that got us here.
     182             :   CallBuiltin(Builtins::kRejectPromise, context, promise, reason,
     183         112 :               FalseConstant());
     184             : 
     185          56 :   Label if_debugging(this, Label::kDeferred);
     186         112 :   GotoIf(HasAsyncEventDelegate(), &if_debugging);
     187         112 :   GotoIf(IsDebugActive(), &if_debugging);
     188          56 :   Return(promise);
     189             : 
     190          56 :   BIND(&if_debugging);
     191          56 :   TailCallRuntime(Runtime::kDebugAsyncFunctionFinished, context, can_suspend,
     192          56 :                   promise);
     193          56 : }
     194             : 
     195         336 : TF_BUILTIN(AsyncFunctionResolve, AsyncFunctionBuiltinsAssembler) {
     196             :   TNode<JSAsyncFunctionObject> async_function_object =
     197             :       CAST(Parameter(Descriptor::kAsyncFunctionObject));
     198          56 :   TNode<Object> value = CAST(Parameter(Descriptor::kValue));
     199          56 :   TNode<Oddball> can_suspend = CAST(Parameter(Descriptor::kCanSuspend));
     200             :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     201             :   TNode<JSPromise> promise = LoadObjectField<JSPromise>(
     202          56 :       async_function_object, JSAsyncFunctionObject::kPromiseOffset);
     203             : 
     204          56 :   CallBuiltin(Builtins::kResolvePromise, context, promise, value);
     205             : 
     206          56 :   Label if_debugging(this, Label::kDeferred);
     207         112 :   GotoIf(HasAsyncEventDelegate(), &if_debugging);
     208         112 :   GotoIf(IsDebugActive(), &if_debugging);
     209          56 :   Return(promise);
     210             : 
     211          56 :   BIND(&if_debugging);
     212          56 :   TailCallRuntime(Runtime::kDebugAsyncFunctionFinished, context, can_suspend,
     213          56 :                   promise);
     214          56 : }
     215             : 
     216             : // AsyncFunctionReject and AsyncFunctionResolve are both required to return
     217             : // the promise instead of the result of RejectPromise or ResolvePromise
     218             : // respectively from a lazy deoptimization.
     219         224 : TF_BUILTIN(AsyncFunctionLazyDeoptContinuation, AsyncFunctionBuiltinsAssembler) {
     220             :   TNode<JSPromise> promise = CAST(Parameter(Descriptor::kPromise));
     221          56 :   Return(promise);
     222          56 : }
     223             : 
     224         224 : TF_BUILTIN(AsyncFunctionAwaitRejectClosure, AsyncFunctionBuiltinsAssembler) {
     225             :   CSA_ASSERT_JS_ARGC_EQ(this, 1);
     226             :   Node* const sentError = Parameter(Descriptor::kSentError);
     227             :   Node* const context = Parameter(Descriptor::kContext);
     228             : 
     229          56 :   AsyncFunctionAwaitResumeClosure(context, sentError,
     230          56 :                                   JSGeneratorObject::kThrow);
     231         112 :   Return(UndefinedConstant());
     232          56 : }
     233             : 
     234         224 : TF_BUILTIN(AsyncFunctionAwaitResolveClosure, AsyncFunctionBuiltinsAssembler) {
     235             :   CSA_ASSERT_JS_ARGC_EQ(this, 1);
     236             :   Node* const sentValue = Parameter(Descriptor::kSentValue);
     237             :   Node* const context = Parameter(Descriptor::kContext);
     238             : 
     239          56 :   AsyncFunctionAwaitResumeClosure(context, sentValue, JSGeneratorObject::kNext);
     240         112 :   Return(UndefinedConstant());
     241          56 : }
     242             : 
     243             : // ES#abstract-ops-async-function-await
     244             : // AsyncFunctionAwait ( value )
     245             : // Shared logic for the core of await. The parser desugars
     246             : //   await value
     247             : // into
     248             : //   yield AsyncFunctionAwait{Caught,Uncaught}(.generator_object, value)
     249             : // The 'value' parameter is the value; the .generator_object stands in
     250             : // for the asyncContext.
     251             : template <typename Descriptor>
     252         112 : void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait(
     253             :     const bool is_predicted_as_caught) {
     254             :   TNode<JSAsyncFunctionObject> async_function_object =
     255         112 :       CAST(Parameter(Descriptor::kAsyncFunctionObject));
     256         112 :   TNode<Object> value = CAST(Parameter(Descriptor::kValue));
     257         112 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     258             : 
     259         112 :   Node* outer_promise = LoadObjectField(async_function_object,
     260             :                                         JSAsyncFunctionObject::kPromiseOffset);
     261             : 
     262         112 :   Label after_debug_hook(this), call_debug_hook(this, Label::kDeferred);
     263         224 :   GotoIf(HasAsyncEventDelegate(), &call_debug_hook);
     264         112 :   Goto(&after_debug_hook);
     265         112 :   BIND(&after_debug_hook);
     266             : 
     267         112 :   Await(context, async_function_object, value, outer_promise,
     268             :         Context::ASYNC_FUNCTION_AWAIT_RESOLVE_SHARED_FUN,
     269             :         Context::ASYNC_FUNCTION_AWAIT_REJECT_SHARED_FUN,
     270             :         is_predicted_as_caught);
     271             : 
     272             :   // Return outer promise to avoid adding an load of the outer promise before
     273             :   // suspending in BytecodeGenerator.
     274         112 :   Return(outer_promise);
     275             : 
     276         112 :   BIND(&call_debug_hook);
     277             :   CallRuntime(Runtime::kDebugAsyncFunctionSuspended, context, outer_promise);
     278         112 :   Goto(&after_debug_hook);
     279         112 : }
     280             : 
     281             : // Called by the parser from the desugaring of 'await' when catch
     282             : // prediction indicates that there is a locally surrounding catch block.
     283         168 : TF_BUILTIN(AsyncFunctionAwaitCaught, AsyncFunctionBuiltinsAssembler) {
     284             :   static const bool kIsPredictedAsCaught = true;
     285          56 :   AsyncFunctionAwait<Descriptor>(kIsPredictedAsCaught);
     286           0 : }
     287             : 
     288             : // Called by the parser from the desugaring of 'await' when catch
     289             : // prediction indicates no locally surrounding catch block.
     290         168 : TF_BUILTIN(AsyncFunctionAwaitUncaught, AsyncFunctionBuiltinsAssembler) {
     291             :   static const bool kIsPredictedAsCaught = false;
     292          56 :   AsyncFunctionAwait<Descriptor>(kIsPredictedAsCaught);
     293           0 : }
     294             : 
     295             : }  // namespace internal
     296       59456 : }  // namespace v8

Generated by: LCOV version 1.10