11cb0ef41Sopenharmony_ci// Copyright 2016 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 71cb0ef41Sopenharmony_ci#include "src/builtins/builtins-utils-gen.h" 81cb0ef41Sopenharmony_ci#include "src/heap/factory-inl.h" 91cb0ef41Sopenharmony_ci#include "src/objects/js-generator.h" 101cb0ef41Sopenharmony_ci#include "src/objects/js-promise.h" 111cb0ef41Sopenharmony_ci#include "src/objects/shared-function-info.h" 121cb0ef41Sopenharmony_ci 131cb0ef41Sopenharmony_cinamespace v8 { 141cb0ef41Sopenharmony_cinamespace internal { 151cb0ef41Sopenharmony_ci 161cb0ef41Sopenharmony_cinamespace { 171cb0ef41Sopenharmony_ci// Describe fields of Context associated with the AsyncIterator unwrap closure. 181cb0ef41Sopenharmony_ciclass ValueUnwrapContext { 191cb0ef41Sopenharmony_ci public: 201cb0ef41Sopenharmony_ci enum Fields { kDoneSlot = Context::MIN_CONTEXT_SLOTS, kLength }; 211cb0ef41Sopenharmony_ci}; 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_ci} // namespace 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_ciTNode<Object> AsyncBuiltinsAssembler::Await( 261cb0ef41Sopenharmony_ci TNode<Context> context, TNode<JSGeneratorObject> generator, 271cb0ef41Sopenharmony_ci TNode<Object> value, TNode<JSPromise> outer_promise, 281cb0ef41Sopenharmony_ci TNode<SharedFunctionInfo> on_resolve_sfi, 291cb0ef41Sopenharmony_ci TNode<SharedFunctionInfo> on_reject_sfi, 301cb0ef41Sopenharmony_ci TNode<Oddball> is_predicted_as_caught) { 311cb0ef41Sopenharmony_ci const TNode<NativeContext> native_context = LoadNativeContext(context); 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ci // We do the `PromiseResolve(%Promise%,value)` avoiding to unnecessarily 341cb0ef41Sopenharmony_ci // create wrapper promises. Now if {value} is already a promise with the 351cb0ef41Sopenharmony_ci // intrinsics %Promise% constructor as its "constructor", we don't need 361cb0ef41Sopenharmony_ci // to allocate the wrapper promise. 371cb0ef41Sopenharmony_ci { 381cb0ef41Sopenharmony_ci TVARIABLE(Object, var_value, value); 391cb0ef41Sopenharmony_ci Label if_slow_path(this, Label::kDeferred), if_done(this), 401cb0ef41Sopenharmony_ci if_slow_constructor(this, Label::kDeferred); 411cb0ef41Sopenharmony_ci GotoIf(TaggedIsSmi(value), &if_slow_path); 421cb0ef41Sopenharmony_ci TNode<HeapObject> value_object = CAST(value); 431cb0ef41Sopenharmony_ci const TNode<Map> value_map = LoadMap(value_object); 441cb0ef41Sopenharmony_ci GotoIfNot(IsJSPromiseMap(value_map), &if_slow_path); 451cb0ef41Sopenharmony_ci // We can skip the "constructor" lookup on {value} if it's [[Prototype]] 461cb0ef41Sopenharmony_ci // is the (initial) Promise.prototype and the @@species protector is 471cb0ef41Sopenharmony_ci // intact, as that guards the lookup path for "constructor" on 481cb0ef41Sopenharmony_ci // JSPromise instances which have the (initial) Promise.prototype. 491cb0ef41Sopenharmony_ci const TNode<Object> promise_prototype = 501cb0ef41Sopenharmony_ci LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_INDEX); 511cb0ef41Sopenharmony_ci GotoIfNot(TaggedEqual(LoadMapPrototype(value_map), promise_prototype), 521cb0ef41Sopenharmony_ci &if_slow_constructor); 531cb0ef41Sopenharmony_ci Branch(IsPromiseSpeciesProtectorCellInvalid(), &if_slow_constructor, 541cb0ef41Sopenharmony_ci &if_done); 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_ci // At this point, {value} doesn't have the initial promise prototype or 571cb0ef41Sopenharmony_ci // the promise @@species protector was invalidated, but {value} could still 581cb0ef41Sopenharmony_ci // have the %Promise% as its "constructor", so we need to check that as 591cb0ef41Sopenharmony_ci // well. 601cb0ef41Sopenharmony_ci BIND(&if_slow_constructor); 611cb0ef41Sopenharmony_ci { 621cb0ef41Sopenharmony_ci const TNode<Object> value_constructor = GetProperty( 631cb0ef41Sopenharmony_ci context, value, isolate()->factory()->constructor_string()); 641cb0ef41Sopenharmony_ci const TNode<Object> promise_function = 651cb0ef41Sopenharmony_ci LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); 661cb0ef41Sopenharmony_ci Branch(TaggedEqual(value_constructor, promise_function), &if_done, 671cb0ef41Sopenharmony_ci &if_slow_path); 681cb0ef41Sopenharmony_ci } 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_ci BIND(&if_slow_path); 711cb0ef41Sopenharmony_ci { 721cb0ef41Sopenharmony_ci // We need to mark the {value} wrapper as having {outer_promise} 731cb0ef41Sopenharmony_ci // as its parent, which is why we need to inline a good chunk of 741cb0ef41Sopenharmony_ci // logic from the `PromiseResolve` builtin here. 751cb0ef41Sopenharmony_ci var_value = NewJSPromise(native_context, outer_promise); 761cb0ef41Sopenharmony_ci CallBuiltin(Builtin::kResolvePromise, native_context, var_value.value(), 771cb0ef41Sopenharmony_ci value); 781cb0ef41Sopenharmony_ci Goto(&if_done); 791cb0ef41Sopenharmony_ci } 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci BIND(&if_done); 821cb0ef41Sopenharmony_ci value = var_value.value(); 831cb0ef41Sopenharmony_ci } 841cb0ef41Sopenharmony_ci 851cb0ef41Sopenharmony_ci static const int kClosureContextSize = 861cb0ef41Sopenharmony_ci FixedArray::SizeFor(Context::MIN_CONTEXT_EXTENDED_SLOTS); 871cb0ef41Sopenharmony_ci TNode<Context> closure_context = 881cb0ef41Sopenharmony_ci UncheckedCast<Context>(AllocateInNewSpace(kClosureContextSize)); 891cb0ef41Sopenharmony_ci { 901cb0ef41Sopenharmony_ci // Initialize the await context, storing the {generator} as extension. 911cb0ef41Sopenharmony_ci TNode<Map> map = CAST( 921cb0ef41Sopenharmony_ci LoadContextElement(native_context, Context::AWAIT_CONTEXT_MAP_INDEX)); 931cb0ef41Sopenharmony_ci StoreMapNoWriteBarrier(closure_context, map); 941cb0ef41Sopenharmony_ci StoreObjectFieldNoWriteBarrier( 951cb0ef41Sopenharmony_ci closure_context, Context::kLengthOffset, 961cb0ef41Sopenharmony_ci SmiConstant(Context::MIN_CONTEXT_EXTENDED_SLOTS)); 971cb0ef41Sopenharmony_ci const TNode<Object> empty_scope_info = 981cb0ef41Sopenharmony_ci LoadContextElement(native_context, Context::SCOPE_INFO_INDEX); 991cb0ef41Sopenharmony_ci StoreContextElementNoWriteBarrier( 1001cb0ef41Sopenharmony_ci closure_context, Context::SCOPE_INFO_INDEX, empty_scope_info); 1011cb0ef41Sopenharmony_ci StoreContextElementNoWriteBarrier(closure_context, Context::PREVIOUS_INDEX, 1021cb0ef41Sopenharmony_ci native_context); 1031cb0ef41Sopenharmony_ci StoreContextElementNoWriteBarrier(closure_context, Context::EXTENSION_INDEX, 1041cb0ef41Sopenharmony_ci generator); 1051cb0ef41Sopenharmony_ci } 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ci // Allocate and initialize resolve handler 1081cb0ef41Sopenharmony_ci TNode<HeapObject> on_resolve = 1091cb0ef41Sopenharmony_ci AllocateInNewSpace(JSFunction::kSizeWithoutPrototype); 1101cb0ef41Sopenharmony_ci InitializeNativeClosure(closure_context, native_context, on_resolve, 1111cb0ef41Sopenharmony_ci on_resolve_sfi); 1121cb0ef41Sopenharmony_ci 1131cb0ef41Sopenharmony_ci // Allocate and initialize reject handler 1141cb0ef41Sopenharmony_ci TNode<HeapObject> on_reject = 1151cb0ef41Sopenharmony_ci AllocateInNewSpace(JSFunction::kSizeWithoutPrototype); 1161cb0ef41Sopenharmony_ci InitializeNativeClosure(closure_context, native_context, on_reject, 1171cb0ef41Sopenharmony_ci on_reject_sfi); 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_ci // Deal with PromiseHooks and debug support in the runtime. This 1201cb0ef41Sopenharmony_ci // also allocates the throwaway promise, which is only needed in 1211cb0ef41Sopenharmony_ci // case of PromiseHooks or debugging. 1221cb0ef41Sopenharmony_ci TVARIABLE(Object, var_throwaway, UndefinedConstant()); 1231cb0ef41Sopenharmony_ci Label if_instrumentation(this, Label::kDeferred), 1241cb0ef41Sopenharmony_ci if_instrumentation_done(this); 1251cb0ef41Sopenharmony_ci TNode<Uint32T> promiseHookFlags = PromiseHookFlags(); 1261cb0ef41Sopenharmony_ci GotoIf(IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate( 1271cb0ef41Sopenharmony_ci promiseHookFlags), 1281cb0ef41Sopenharmony_ci &if_instrumentation); 1291cb0ef41Sopenharmony_ci#ifdef V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS 1301cb0ef41Sopenharmony_ci // This call to NewJSPromise is to keep behaviour parity with what happens 1311cb0ef41Sopenharmony_ci // in Runtime::kDebugAsyncFunctionSuspended below if native hooks are set. 1321cb0ef41Sopenharmony_ci // It creates a throwaway promise that will trigger an init event and get 1331cb0ef41Sopenharmony_ci // passed into Builtin::kPerformPromiseThen below. 1341cb0ef41Sopenharmony_ci GotoIfNot(IsContextPromiseHookEnabled(promiseHookFlags), 1351cb0ef41Sopenharmony_ci &if_instrumentation_done); 1361cb0ef41Sopenharmony_ci var_throwaway = NewJSPromise(context, value); 1371cb0ef41Sopenharmony_ci#endif // V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS 1381cb0ef41Sopenharmony_ci Goto(&if_instrumentation_done); 1391cb0ef41Sopenharmony_ci BIND(&if_instrumentation); 1401cb0ef41Sopenharmony_ci { 1411cb0ef41Sopenharmony_ci var_throwaway = CallRuntime(Runtime::kDebugAsyncFunctionSuspended, 1421cb0ef41Sopenharmony_ci native_context, value, outer_promise, on_reject, 1431cb0ef41Sopenharmony_ci generator, is_predicted_as_caught); 1441cb0ef41Sopenharmony_ci Goto(&if_instrumentation_done); 1451cb0ef41Sopenharmony_ci } 1461cb0ef41Sopenharmony_ci BIND(&if_instrumentation_done); 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_ci return CallBuiltin(Builtin::kPerformPromiseThen, native_context, value, 1491cb0ef41Sopenharmony_ci on_resolve, on_reject, var_throwaway.value()); 1501cb0ef41Sopenharmony_ci} 1511cb0ef41Sopenharmony_ci 1521cb0ef41Sopenharmony_civoid AsyncBuiltinsAssembler::InitializeNativeClosure( 1531cb0ef41Sopenharmony_ci TNode<Context> context, TNode<NativeContext> native_context, 1541cb0ef41Sopenharmony_ci TNode<HeapObject> function, TNode<SharedFunctionInfo> shared_info) { 1551cb0ef41Sopenharmony_ci TNode<Map> function_map = CAST(LoadContextElement( 1561cb0ef41Sopenharmony_ci native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX)); 1571cb0ef41Sopenharmony_ci // Ensure that we don't have to initialize prototype_or_initial_map field of 1581cb0ef41Sopenharmony_ci // JSFunction. 1591cb0ef41Sopenharmony_ci CSA_DCHECK(this, 1601cb0ef41Sopenharmony_ci IntPtrEqual(LoadMapInstanceSizeInWords(function_map), 1611cb0ef41Sopenharmony_ci IntPtrConstant(JSFunction::kSizeWithoutPrototype / 1621cb0ef41Sopenharmony_ci kTaggedSize))); 1631cb0ef41Sopenharmony_ci STATIC_ASSERT(JSFunction::kSizeWithoutPrototype == 7 * kTaggedSize); 1641cb0ef41Sopenharmony_ci StoreMapNoWriteBarrier(function, function_map); 1651cb0ef41Sopenharmony_ci StoreObjectFieldRoot(function, JSObject::kPropertiesOrHashOffset, 1661cb0ef41Sopenharmony_ci RootIndex::kEmptyFixedArray); 1671cb0ef41Sopenharmony_ci StoreObjectFieldRoot(function, JSObject::kElementsOffset, 1681cb0ef41Sopenharmony_ci RootIndex::kEmptyFixedArray); 1691cb0ef41Sopenharmony_ci StoreObjectFieldRoot(function, JSFunction::kFeedbackCellOffset, 1701cb0ef41Sopenharmony_ci RootIndex::kManyClosuresCell); 1711cb0ef41Sopenharmony_ci 1721cb0ef41Sopenharmony_ci StoreObjectFieldNoWriteBarrier( 1731cb0ef41Sopenharmony_ci function, JSFunction::kSharedFunctionInfoOffset, shared_info); 1741cb0ef41Sopenharmony_ci StoreObjectFieldNoWriteBarrier(function, JSFunction::kContextOffset, context); 1751cb0ef41Sopenharmony_ci 1761cb0ef41Sopenharmony_ci // For the native closures that are initialized here (for `await`) 1771cb0ef41Sopenharmony_ci // we know that their SharedFunctionInfo::function_data(kAcquireLoad) slot 1781cb0ef41Sopenharmony_ci // contains a builtin index (as Smi), so there's no need to use 1791cb0ef41Sopenharmony_ci // CodeStubAssembler::GetSharedFunctionInfoCode() helper here, 1801cb0ef41Sopenharmony_ci // which almost doubles the size of `await` builtins (unnecessarily). 1811cb0ef41Sopenharmony_ci TNode<Smi> builtin_id = LoadObjectField<Smi>( 1821cb0ef41Sopenharmony_ci shared_info, SharedFunctionInfo::kFunctionDataOffset); 1831cb0ef41Sopenharmony_ci TNode<CodeT> code = LoadBuiltin(builtin_id); 1841cb0ef41Sopenharmony_ci StoreObjectFieldNoWriteBarrier(function, JSFunction::kCodeOffset, code); 1851cb0ef41Sopenharmony_ci} 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_ciTNode<JSFunction> AsyncBuiltinsAssembler::CreateUnwrapClosure( 1881cb0ef41Sopenharmony_ci TNode<NativeContext> native_context, TNode<Oddball> done) { 1891cb0ef41Sopenharmony_ci const TNode<Map> map = CAST(LoadContextElement( 1901cb0ef41Sopenharmony_ci native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX)); 1911cb0ef41Sopenharmony_ci const TNode<SharedFunctionInfo> on_fulfilled_shared = 1921cb0ef41Sopenharmony_ci AsyncIteratorValueUnwrapSharedFunConstant(); 1931cb0ef41Sopenharmony_ci const TNode<Context> closure_context = 1941cb0ef41Sopenharmony_ci AllocateAsyncIteratorValueUnwrapContext(native_context, done); 1951cb0ef41Sopenharmony_ci return AllocateFunctionWithMapAndContext(map, on_fulfilled_shared, 1961cb0ef41Sopenharmony_ci closure_context); 1971cb0ef41Sopenharmony_ci} 1981cb0ef41Sopenharmony_ci 1991cb0ef41Sopenharmony_ciTNode<Context> AsyncBuiltinsAssembler::AllocateAsyncIteratorValueUnwrapContext( 2001cb0ef41Sopenharmony_ci TNode<NativeContext> native_context, TNode<Oddball> done) { 2011cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsBoolean(done)); 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_ci TNode<Context> context = AllocateSyntheticFunctionContext( 2041cb0ef41Sopenharmony_ci native_context, ValueUnwrapContext::kLength); 2051cb0ef41Sopenharmony_ci StoreContextElementNoWriteBarrier(context, ValueUnwrapContext::kDoneSlot, 2061cb0ef41Sopenharmony_ci done); 2071cb0ef41Sopenharmony_ci return context; 2081cb0ef41Sopenharmony_ci} 2091cb0ef41Sopenharmony_ci 2101cb0ef41Sopenharmony_ciTF_BUILTIN(AsyncIteratorValueUnwrap, AsyncBuiltinsAssembler) { 2111cb0ef41Sopenharmony_ci auto value = Parameter<Object>(Descriptor::kValue); 2121cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 2131cb0ef41Sopenharmony_ci 2141cb0ef41Sopenharmony_ci const TNode<Object> done = 2151cb0ef41Sopenharmony_ci LoadContextElement(context, ValueUnwrapContext::kDoneSlot); 2161cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsBoolean(CAST(done))); 2171cb0ef41Sopenharmony_ci 2181cb0ef41Sopenharmony_ci const TNode<Object> unwrapped_value = 2191cb0ef41Sopenharmony_ci CallBuiltin(Builtin::kCreateIterResultObject, context, value, done); 2201cb0ef41Sopenharmony_ci 2211cb0ef41Sopenharmony_ci Return(unwrapped_value); 2221cb0ef41Sopenharmony_ci} 2231cb0ef41Sopenharmony_ci 2241cb0ef41Sopenharmony_ci} // namespace internal 2251cb0ef41Sopenharmony_ci} // namespace v8 226