11cb0ef41Sopenharmony_ci// Copyright 2017 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "src/builtins/builtins-async-gen.h"
61cb0ef41Sopenharmony_ci#include "src/builtins/builtins-utils-gen.h"
71cb0ef41Sopenharmony_ci#include "src/builtins/builtins.h"
81cb0ef41Sopenharmony_ci#include "src/codegen/code-stub-assembler.h"
91cb0ef41Sopenharmony_ci#include "src/objects/js-generator.h"
101cb0ef41Sopenharmony_ci#include "src/objects/js-promise.h"
111cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h"
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_cinamespace v8 {
141cb0ef41Sopenharmony_cinamespace internal {
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ciclass AsyncFunctionBuiltinsAssembler : public AsyncBuiltinsAssembler {
171cb0ef41Sopenharmony_ci public:
181cb0ef41Sopenharmony_ci  explicit AsyncFunctionBuiltinsAssembler(compiler::CodeAssemblerState* state)
191cb0ef41Sopenharmony_ci      : AsyncBuiltinsAssembler(state) {}
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ci protected:
221cb0ef41Sopenharmony_ci  template <typename Descriptor>
231cb0ef41Sopenharmony_ci  void AsyncFunctionAwait(const bool is_predicted_as_caught);
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci  void AsyncFunctionAwaitResumeClosure(
261cb0ef41Sopenharmony_ci      const TNode<Context> context, const TNode<Object> sent_value,
271cb0ef41Sopenharmony_ci      JSGeneratorObject::ResumeMode resume_mode);
281cb0ef41Sopenharmony_ci};
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_civoid AsyncFunctionBuiltinsAssembler::AsyncFunctionAwaitResumeClosure(
311cb0ef41Sopenharmony_ci    TNode<Context> context, TNode<Object> sent_value,
321cb0ef41Sopenharmony_ci    JSGeneratorObject::ResumeMode resume_mode) {
331cb0ef41Sopenharmony_ci  DCHECK(resume_mode == JSGeneratorObject::kNext ||
341cb0ef41Sopenharmony_ci         resume_mode == JSGeneratorObject::kThrow);
351cb0ef41Sopenharmony_ci
361cb0ef41Sopenharmony_ci  TNode<JSAsyncFunctionObject> async_function_object =
371cb0ef41Sopenharmony_ci      CAST(LoadContextElement(context, Context::EXTENSION_INDEX));
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci  // Push the promise for the {async_function_object} back onto the catch
401cb0ef41Sopenharmony_ci  // prediction stack to handle exceptions thrown after resuming from the
411cb0ef41Sopenharmony_ci  // await properly.
421cb0ef41Sopenharmony_ci  Label if_instrumentation(this, Label::kDeferred),
431cb0ef41Sopenharmony_ci      if_instrumentation_done(this);
441cb0ef41Sopenharmony_ci  Branch(IsDebugActive(), &if_instrumentation, &if_instrumentation_done);
451cb0ef41Sopenharmony_ci  BIND(&if_instrumentation);
461cb0ef41Sopenharmony_ci  {
471cb0ef41Sopenharmony_ci    TNode<JSPromise> promise = LoadObjectField<JSPromise>(
481cb0ef41Sopenharmony_ci        async_function_object, JSAsyncFunctionObject::kPromiseOffset);
491cb0ef41Sopenharmony_ci    CallRuntime(Runtime::kDebugPushPromise, context, promise);
501cb0ef41Sopenharmony_ci    Goto(&if_instrumentation_done);
511cb0ef41Sopenharmony_ci  }
521cb0ef41Sopenharmony_ci  BIND(&if_instrumentation_done);
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ci  // Inline version of GeneratorPrototypeNext / GeneratorPrototypeReturn with
551cb0ef41Sopenharmony_ci  // unnecessary runtime checks removed.
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ci  // Ensure that the {async_function_object} is neither closed nor running.
581cb0ef41Sopenharmony_ci  CSA_SLOW_DCHECK(
591cb0ef41Sopenharmony_ci      this, SmiGreaterThan(
601cb0ef41Sopenharmony_ci                LoadObjectField<Smi>(async_function_object,
611cb0ef41Sopenharmony_ci                                     JSGeneratorObject::kContinuationOffset),
621cb0ef41Sopenharmony_ci                SmiConstant(JSGeneratorObject::kGeneratorClosed)));
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ci  // Remember the {resume_mode} for the {async_function_object}.
651cb0ef41Sopenharmony_ci  StoreObjectFieldNoWriteBarrier(async_function_object,
661cb0ef41Sopenharmony_ci                                 JSGeneratorObject::kResumeModeOffset,
671cb0ef41Sopenharmony_ci                                 SmiConstant(resume_mode));
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_ci  // Resume the {receiver} using our trampoline.
701cb0ef41Sopenharmony_ci  Callable callable = CodeFactory::ResumeGenerator(isolate());
711cb0ef41Sopenharmony_ci  CallStub(callable, context, sent_value, async_function_object);
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci  // The resulting Promise is a throwaway, so it doesn't matter what it
741cb0ef41Sopenharmony_ci  // resolves to. What is important is that we don't end up keeping the
751cb0ef41Sopenharmony_ci  // whole chain of intermediate Promises alive by returning the return value
761cb0ef41Sopenharmony_ci  // of ResumeGenerator, as that would create a memory leak.
771cb0ef41Sopenharmony_ci}
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ciTF_BUILTIN(AsyncFunctionEnter, AsyncFunctionBuiltinsAssembler) {
801cb0ef41Sopenharmony_ci  auto closure = Parameter<JSFunction>(Descriptor::kClosure);
811cb0ef41Sopenharmony_ci  auto receiver = Parameter<Object>(Descriptor::kReceiver);
821cb0ef41Sopenharmony_ci  auto context = Parameter<Context>(Descriptor::kContext);
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci  // Compute the number of registers and parameters.
851cb0ef41Sopenharmony_ci  TNode<SharedFunctionInfo> shared = LoadObjectField<SharedFunctionInfo>(
861cb0ef41Sopenharmony_ci      closure, JSFunction::kSharedFunctionInfoOffset);
871cb0ef41Sopenharmony_ci  TNode<IntPtrT> formal_parameter_count = ChangeInt32ToIntPtr(
881cb0ef41Sopenharmony_ci      LoadSharedFunctionInfoFormalParameterCountWithoutReceiver(shared));
891cb0ef41Sopenharmony_ci  TNode<BytecodeArray> bytecode_array =
901cb0ef41Sopenharmony_ci      LoadSharedFunctionInfoBytecodeArray(shared);
911cb0ef41Sopenharmony_ci  TNode<IntPtrT> frame_size = ChangeInt32ToIntPtr(LoadObjectField<Uint32T>(
921cb0ef41Sopenharmony_ci      bytecode_array, BytecodeArray::kFrameSizeOffset));
931cb0ef41Sopenharmony_ci  TNode<IntPtrT> parameters_and_register_length =
941cb0ef41Sopenharmony_ci      Signed(IntPtrAdd(WordSar(frame_size, IntPtrConstant(kTaggedSizeLog2)),
951cb0ef41Sopenharmony_ci                       formal_parameter_count));
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_ci  // Allocate and initialize the register file.
981cb0ef41Sopenharmony_ci  TNode<FixedArrayBase> parameters_and_registers =
991cb0ef41Sopenharmony_ci      AllocateFixedArray(HOLEY_ELEMENTS, parameters_and_register_length,
1001cb0ef41Sopenharmony_ci                         AllocationFlag::kAllowLargeObjectAllocation);
1011cb0ef41Sopenharmony_ci  FillFixedArrayWithValue(HOLEY_ELEMENTS, parameters_and_registers,
1021cb0ef41Sopenharmony_ci                          IntPtrConstant(0), parameters_and_register_length,
1031cb0ef41Sopenharmony_ci                          RootIndex::kUndefinedValue);
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_ci  // Allocate and initialize the promise.
1061cb0ef41Sopenharmony_ci  TNode<JSPromise> promise = NewJSPromise(context);
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ci  // Allocate and initialize the async function object.
1091cb0ef41Sopenharmony_ci  TNode<NativeContext> native_context = LoadNativeContext(context);
1101cb0ef41Sopenharmony_ci  TNode<Map> async_function_object_map = CAST(LoadContextElement(
1111cb0ef41Sopenharmony_ci      native_context, Context::ASYNC_FUNCTION_OBJECT_MAP_INDEX));
1121cb0ef41Sopenharmony_ci  TNode<JSAsyncFunctionObject> async_function_object =
1131cb0ef41Sopenharmony_ci      UncheckedCast<JSAsyncFunctionObject>(
1141cb0ef41Sopenharmony_ci          AllocateInNewSpace(JSAsyncFunctionObject::kHeaderSize));
1151cb0ef41Sopenharmony_ci  StoreMapNoWriteBarrier(async_function_object, async_function_object_map);
1161cb0ef41Sopenharmony_ci  StoreObjectFieldRoot(async_function_object,
1171cb0ef41Sopenharmony_ci                       JSAsyncFunctionObject::kPropertiesOrHashOffset,
1181cb0ef41Sopenharmony_ci                       RootIndex::kEmptyFixedArray);
1191cb0ef41Sopenharmony_ci  StoreObjectFieldRoot(async_function_object,
1201cb0ef41Sopenharmony_ci                       JSAsyncFunctionObject::kElementsOffset,
1211cb0ef41Sopenharmony_ci                       RootIndex::kEmptyFixedArray);
1221cb0ef41Sopenharmony_ci  StoreObjectFieldNoWriteBarrier(
1231cb0ef41Sopenharmony_ci      async_function_object, JSAsyncFunctionObject::kFunctionOffset, closure);
1241cb0ef41Sopenharmony_ci  StoreObjectFieldNoWriteBarrier(
1251cb0ef41Sopenharmony_ci      async_function_object, JSAsyncFunctionObject::kContextOffset, context);
1261cb0ef41Sopenharmony_ci  StoreObjectFieldNoWriteBarrier(
1271cb0ef41Sopenharmony_ci      async_function_object, JSAsyncFunctionObject::kReceiverOffset, receiver);
1281cb0ef41Sopenharmony_ci  StoreObjectFieldNoWriteBarrier(async_function_object,
1291cb0ef41Sopenharmony_ci                                 JSAsyncFunctionObject::kInputOrDebugPosOffset,
1301cb0ef41Sopenharmony_ci                                 SmiConstant(0));
1311cb0ef41Sopenharmony_ci  StoreObjectFieldNoWriteBarrier(async_function_object,
1321cb0ef41Sopenharmony_ci                                 JSAsyncFunctionObject::kResumeModeOffset,
1331cb0ef41Sopenharmony_ci                                 SmiConstant(JSAsyncFunctionObject::kNext));
1341cb0ef41Sopenharmony_ci  StoreObjectFieldNoWriteBarrier(
1351cb0ef41Sopenharmony_ci      async_function_object, JSAsyncFunctionObject::kContinuationOffset,
1361cb0ef41Sopenharmony_ci      SmiConstant(JSAsyncFunctionObject::kGeneratorExecuting));
1371cb0ef41Sopenharmony_ci  StoreObjectFieldNoWriteBarrier(
1381cb0ef41Sopenharmony_ci      async_function_object,
1391cb0ef41Sopenharmony_ci      JSAsyncFunctionObject::kParametersAndRegistersOffset,
1401cb0ef41Sopenharmony_ci      parameters_and_registers);
1411cb0ef41Sopenharmony_ci  StoreObjectFieldNoWriteBarrier(
1421cb0ef41Sopenharmony_ci      async_function_object, JSAsyncFunctionObject::kPromiseOffset, promise);
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ci  // While we are executing an async function, we need to have the implicit
1451cb0ef41Sopenharmony_ci  // promise on the stack to get the catch prediction right, even before we
1461cb0ef41Sopenharmony_ci  // awaited for the first time.
1471cb0ef41Sopenharmony_ci  Label if_debugging(this);
1481cb0ef41Sopenharmony_ci  GotoIf(IsDebugActive(), &if_debugging);
1491cb0ef41Sopenharmony_ci  Return(async_function_object);
1501cb0ef41Sopenharmony_ci
1511cb0ef41Sopenharmony_ci  BIND(&if_debugging);
1521cb0ef41Sopenharmony_ci  CallRuntime(Runtime::kDebugPushPromise, context, promise);
1531cb0ef41Sopenharmony_ci  Return(async_function_object);
1541cb0ef41Sopenharmony_ci}
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_ciTF_BUILTIN(AsyncFunctionReject, AsyncFunctionBuiltinsAssembler) {
1571cb0ef41Sopenharmony_ci  auto async_function_object =
1581cb0ef41Sopenharmony_ci      Parameter<JSAsyncFunctionObject>(Descriptor::kAsyncFunctionObject);
1591cb0ef41Sopenharmony_ci  auto reason = Parameter<Object>(Descriptor::kReason);
1601cb0ef41Sopenharmony_ci  auto context = Parameter<Context>(Descriptor::kContext);
1611cb0ef41Sopenharmony_ci  TNode<JSPromise> promise = LoadObjectField<JSPromise>(
1621cb0ef41Sopenharmony_ci      async_function_object, JSAsyncFunctionObject::kPromiseOffset);
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_ci  // Reject the {promise} for the given {reason}, disabling the
1651cb0ef41Sopenharmony_ci  // additional debug event for the rejection since a debug event
1661cb0ef41Sopenharmony_ci  // already happend for the exception that got us here.
1671cb0ef41Sopenharmony_ci  CallBuiltin(Builtin::kRejectPromise, context, promise, reason,
1681cb0ef41Sopenharmony_ci              FalseConstant());
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_ci  Label if_debugging(this);
1711cb0ef41Sopenharmony_ci  GotoIf(IsDebugActive(), &if_debugging);
1721cb0ef41Sopenharmony_ci  Return(promise);
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci  BIND(&if_debugging);
1751cb0ef41Sopenharmony_ci  CallRuntime(Runtime::kDebugPopPromise, context);
1761cb0ef41Sopenharmony_ci  Return(promise);
1771cb0ef41Sopenharmony_ci}
1781cb0ef41Sopenharmony_ci
1791cb0ef41Sopenharmony_ciTF_BUILTIN(AsyncFunctionResolve, AsyncFunctionBuiltinsAssembler) {
1801cb0ef41Sopenharmony_ci  auto async_function_object =
1811cb0ef41Sopenharmony_ci      Parameter<JSAsyncFunctionObject>(Descriptor::kAsyncFunctionObject);
1821cb0ef41Sopenharmony_ci  auto value = Parameter<Object>(Descriptor::kValue);
1831cb0ef41Sopenharmony_ci  auto context = Parameter<Context>(Descriptor::kContext);
1841cb0ef41Sopenharmony_ci  TNode<JSPromise> promise = LoadObjectField<JSPromise>(
1851cb0ef41Sopenharmony_ci      async_function_object, JSAsyncFunctionObject::kPromiseOffset);
1861cb0ef41Sopenharmony_ci
1871cb0ef41Sopenharmony_ci  CallBuiltin(Builtin::kResolvePromise, context, promise, value);
1881cb0ef41Sopenharmony_ci
1891cb0ef41Sopenharmony_ci  Label if_debugging(this);
1901cb0ef41Sopenharmony_ci  GotoIf(IsDebugActive(), &if_debugging);
1911cb0ef41Sopenharmony_ci  Return(promise);
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_ci  BIND(&if_debugging);
1941cb0ef41Sopenharmony_ci  CallRuntime(Runtime::kDebugPopPromise, context);
1951cb0ef41Sopenharmony_ci  Return(promise);
1961cb0ef41Sopenharmony_ci}
1971cb0ef41Sopenharmony_ci
1981cb0ef41Sopenharmony_ci// AsyncFunctionReject and AsyncFunctionResolve are both required to return
1991cb0ef41Sopenharmony_ci// the promise instead of the result of RejectPromise or ResolvePromise
2001cb0ef41Sopenharmony_ci// respectively from a lazy deoptimization.
2011cb0ef41Sopenharmony_ciTF_BUILTIN(AsyncFunctionLazyDeoptContinuation, AsyncFunctionBuiltinsAssembler) {
2021cb0ef41Sopenharmony_ci  auto promise = Parameter<JSPromise>(Descriptor::kPromise);
2031cb0ef41Sopenharmony_ci  Return(promise);
2041cb0ef41Sopenharmony_ci}
2051cb0ef41Sopenharmony_ci
2061cb0ef41Sopenharmony_ciTF_BUILTIN(AsyncFunctionAwaitRejectClosure, AsyncFunctionBuiltinsAssembler) {
2071cb0ef41Sopenharmony_ci  CSA_DCHECK_JS_ARGC_EQ(this, 1);
2081cb0ef41Sopenharmony_ci  const auto sentError = Parameter<Object>(Descriptor::kSentError);
2091cb0ef41Sopenharmony_ci  const auto context = Parameter<Context>(Descriptor::kContext);
2101cb0ef41Sopenharmony_ci
2111cb0ef41Sopenharmony_ci  AsyncFunctionAwaitResumeClosure(context, sentError,
2121cb0ef41Sopenharmony_ci                                  JSGeneratorObject::kThrow);
2131cb0ef41Sopenharmony_ci  Return(UndefinedConstant());
2141cb0ef41Sopenharmony_ci}
2151cb0ef41Sopenharmony_ci
2161cb0ef41Sopenharmony_ciTF_BUILTIN(AsyncFunctionAwaitResolveClosure, AsyncFunctionBuiltinsAssembler) {
2171cb0ef41Sopenharmony_ci  CSA_DCHECK_JS_ARGC_EQ(this, 1);
2181cb0ef41Sopenharmony_ci  const auto sentValue = Parameter<Object>(Descriptor::kSentValue);
2191cb0ef41Sopenharmony_ci  const auto context = Parameter<Context>(Descriptor::kContext);
2201cb0ef41Sopenharmony_ci
2211cb0ef41Sopenharmony_ci  AsyncFunctionAwaitResumeClosure(context, sentValue, JSGeneratorObject::kNext);
2221cb0ef41Sopenharmony_ci  Return(UndefinedConstant());
2231cb0ef41Sopenharmony_ci}
2241cb0ef41Sopenharmony_ci
2251cb0ef41Sopenharmony_ci// ES#abstract-ops-async-function-await
2261cb0ef41Sopenharmony_ci// AsyncFunctionAwait ( value )
2271cb0ef41Sopenharmony_ci// Shared logic for the core of await. The parser desugars
2281cb0ef41Sopenharmony_ci//   await value
2291cb0ef41Sopenharmony_ci// into
2301cb0ef41Sopenharmony_ci//   yield AsyncFunctionAwait{Caught,Uncaught}(.generator_object, value)
2311cb0ef41Sopenharmony_ci// The 'value' parameter is the value; the .generator_object stands in
2321cb0ef41Sopenharmony_ci// for the asyncContext.
2331cb0ef41Sopenharmony_citemplate <typename Descriptor>
2341cb0ef41Sopenharmony_civoid AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait(
2351cb0ef41Sopenharmony_ci    const bool is_predicted_as_caught) {
2361cb0ef41Sopenharmony_ci  auto async_function_object =
2371cb0ef41Sopenharmony_ci      Parameter<JSAsyncFunctionObject>(Descriptor::kAsyncFunctionObject);
2381cb0ef41Sopenharmony_ci  auto value = Parameter<Object>(Descriptor::kValue);
2391cb0ef41Sopenharmony_ci  auto context = Parameter<Context>(Descriptor::kContext);
2401cb0ef41Sopenharmony_ci
2411cb0ef41Sopenharmony_ci  TNode<SharedFunctionInfo> on_resolve_sfi =
2421cb0ef41Sopenharmony_ci      AsyncFunctionAwaitResolveSharedFunConstant();
2431cb0ef41Sopenharmony_ci  TNode<SharedFunctionInfo> on_reject_sfi =
2441cb0ef41Sopenharmony_ci      AsyncFunctionAwaitRejectSharedFunConstant();
2451cb0ef41Sopenharmony_ci  TNode<JSPromise> outer_promise = LoadObjectField<JSPromise>(
2461cb0ef41Sopenharmony_ci      async_function_object, JSAsyncFunctionObject::kPromiseOffset);
2471cb0ef41Sopenharmony_ci  Await(context, async_function_object, value, outer_promise, on_resolve_sfi,
2481cb0ef41Sopenharmony_ci        on_reject_sfi, is_predicted_as_caught);
2491cb0ef41Sopenharmony_ci
2501cb0ef41Sopenharmony_ci  // Return outer promise to avoid adding an load of the outer promise before
2511cb0ef41Sopenharmony_ci  // suspending in BytecodeGenerator.
2521cb0ef41Sopenharmony_ci  Return(outer_promise);
2531cb0ef41Sopenharmony_ci}
2541cb0ef41Sopenharmony_ci
2551cb0ef41Sopenharmony_ci// Called by the parser from the desugaring of 'await' when catch
2561cb0ef41Sopenharmony_ci// prediction indicates that there is a locally surrounding catch block.
2571cb0ef41Sopenharmony_ciTF_BUILTIN(AsyncFunctionAwaitCaught, AsyncFunctionBuiltinsAssembler) {
2581cb0ef41Sopenharmony_ci  static const bool kIsPredictedAsCaught = true;
2591cb0ef41Sopenharmony_ci  AsyncFunctionAwait<Descriptor>(kIsPredictedAsCaught);
2601cb0ef41Sopenharmony_ci}
2611cb0ef41Sopenharmony_ci
2621cb0ef41Sopenharmony_ci// Called by the parser from the desugaring of 'await' when catch
2631cb0ef41Sopenharmony_ci// prediction indicates no locally surrounding catch block.
2641cb0ef41Sopenharmony_ciTF_BUILTIN(AsyncFunctionAwaitUncaught, AsyncFunctionBuiltinsAssembler) {
2651cb0ef41Sopenharmony_ci  static const bool kIsPredictedAsCaught = false;
2661cb0ef41Sopenharmony_ci  AsyncFunctionAwait<Descriptor>(kIsPredictedAsCaught);
2671cb0ef41Sopenharmony_ci}
2681cb0ef41Sopenharmony_ci
2691cb0ef41Sopenharmony_ci}  // namespace internal
2701cb0ef41Sopenharmony_ci}  // namespace v8
271