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