11cb0ef41Sopenharmony_ci// Copyright 2018 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-lazy-gen.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include "src/builtins/builtins-utils-gen.h" 81cb0ef41Sopenharmony_ci#include "src/builtins/builtins.h" 91cb0ef41Sopenharmony_ci#include "src/common/globals.h" 101cb0ef41Sopenharmony_ci#include "src/objects/code-inl.h" 111cb0ef41Sopenharmony_ci#include "src/objects/feedback-vector.h" 121cb0ef41Sopenharmony_ci#include "src/objects/shared-function-info.h" 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_cinamespace v8 { 151cb0ef41Sopenharmony_cinamespace internal { 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_civoid LazyBuiltinsAssembler::GenerateTailCallToJSCode( 181cb0ef41Sopenharmony_ci TNode<CodeT> code, TNode<JSFunction> function) { 191cb0ef41Sopenharmony_ci auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount); 201cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 211cb0ef41Sopenharmony_ci auto new_target = Parameter<Object>(Descriptor::kNewTarget); 221cb0ef41Sopenharmony_ci TailCallJSCode(code, context, function, new_target, argc); 231cb0ef41Sopenharmony_ci} 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_civoid LazyBuiltinsAssembler::GenerateTailCallToReturnedCode( 261cb0ef41Sopenharmony_ci Runtime::FunctionId function_id, TNode<JSFunction> function) { 271cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 281cb0ef41Sopenharmony_ci TNode<CodeT> code = CAST(CallRuntime(function_id, context, function)); 291cb0ef41Sopenharmony_ci GenerateTailCallToJSCode(code, function); 301cb0ef41Sopenharmony_ci} 311cb0ef41Sopenharmony_ci 321cb0ef41Sopenharmony_civoid LazyBuiltinsAssembler::TailCallRuntimeIfStateEquals( 331cb0ef41Sopenharmony_ci TNode<Uint32T> state, TieringState expected_state, 341cb0ef41Sopenharmony_ci Runtime::FunctionId function_id, TNode<JSFunction> function) { 351cb0ef41Sopenharmony_ci Label no_match(this); 361cb0ef41Sopenharmony_ci GotoIfNot( 371cb0ef41Sopenharmony_ci Word32Equal(state, Uint32Constant(static_cast<uint32_t>(expected_state))), 381cb0ef41Sopenharmony_ci &no_match); 391cb0ef41Sopenharmony_ci GenerateTailCallToReturnedCode(function_id, function); 401cb0ef41Sopenharmony_ci BIND(&no_match); 411cb0ef41Sopenharmony_ci} 421cb0ef41Sopenharmony_ci 431cb0ef41Sopenharmony_civoid LazyBuiltinsAssembler::MaybeTailCallOptimizedCodeSlot( 441cb0ef41Sopenharmony_ci TNode<JSFunction> function, TNode<FeedbackVector> feedback_vector) { 451cb0ef41Sopenharmony_ci Label fallthrough(this), may_have_optimized_code(this); 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ci TNode<Uint32T> optimization_state = 481cb0ef41Sopenharmony_ci LoadObjectField<Uint32T>(feedback_vector, FeedbackVector::kFlagsOffset); 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ci // Fall through if no optimization trigger or optimized code. 511cb0ef41Sopenharmony_ci GotoIfNot( 521cb0ef41Sopenharmony_ci IsSetWord32( 531cb0ef41Sopenharmony_ci optimization_state, 541cb0ef41Sopenharmony_ci FeedbackVector::kHasOptimizedCodeOrTieringStateIsAnyRequestMask), 551cb0ef41Sopenharmony_ci &fallthrough); 561cb0ef41Sopenharmony_ci 571cb0ef41Sopenharmony_ci GotoIfNot(IsSetWord32(optimization_state, 581cb0ef41Sopenharmony_ci FeedbackVector::kTieringStateIsAnyRequestMask), 591cb0ef41Sopenharmony_ci &may_have_optimized_code); 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_ci // TODO(ishell): introduce Runtime::kHandleTieringState and check 621cb0ef41Sopenharmony_ci // all these state values there. 631cb0ef41Sopenharmony_ci TNode<Uint32T> state = 641cb0ef41Sopenharmony_ci DecodeWord32<FeedbackVector::TieringStateBits>(optimization_state); 651cb0ef41Sopenharmony_ci TailCallRuntimeIfStateEquals(state, 661cb0ef41Sopenharmony_ci TieringState::kRequestTurbofan_Synchronous, 671cb0ef41Sopenharmony_ci Runtime::kCompileTurbofan_Synchronous, function); 681cb0ef41Sopenharmony_ci TailCallRuntimeIfStateEquals(state, TieringState::kRequestTurbofan_Concurrent, 691cb0ef41Sopenharmony_ci Runtime::kCompileTurbofan_Concurrent, function); 701cb0ef41Sopenharmony_ci TailCallRuntimeIfStateEquals(state, TieringState::kRequestMaglev_Synchronous, 711cb0ef41Sopenharmony_ci Runtime::kCompileMaglev_Synchronous, function); 721cb0ef41Sopenharmony_ci TailCallRuntimeIfStateEquals(state, TieringState::kRequestMaglev_Concurrent, 731cb0ef41Sopenharmony_ci Runtime::kCompileMaglev_Concurrent, function); 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci Unreachable(); 761cb0ef41Sopenharmony_ci BIND(&may_have_optimized_code); 771cb0ef41Sopenharmony_ci { 781cb0ef41Sopenharmony_ci Label heal_optimized_code_slot(this); 791cb0ef41Sopenharmony_ci TNode<MaybeObject> maybe_optimized_code_entry = LoadMaybeWeakObjectField( 801cb0ef41Sopenharmony_ci feedback_vector, FeedbackVector::kMaybeOptimizedCodeOffset); 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_ci // Optimized code slot is a weak reference to CodeT object. 831cb0ef41Sopenharmony_ci TNode<CodeT> optimized_code = CAST(GetHeapObjectAssumeWeak( 841cb0ef41Sopenharmony_ci maybe_optimized_code_entry, &heal_optimized_code_slot)); 851cb0ef41Sopenharmony_ci 861cb0ef41Sopenharmony_ci // Check if the optimized code is marked for deopt. If it is, call the 871cb0ef41Sopenharmony_ci // runtime to clear it. 881cb0ef41Sopenharmony_ci TNode<CodeDataContainer> code_data_container = 891cb0ef41Sopenharmony_ci CodeDataContainerFromCodeT(optimized_code); 901cb0ef41Sopenharmony_ci TNode<Int32T> code_kind_specific_flags = LoadObjectField<Int32T>( 911cb0ef41Sopenharmony_ci code_data_container, CodeDataContainer::kKindSpecificFlagsOffset); 921cb0ef41Sopenharmony_ci GotoIf(IsSetWord32<Code::MarkedForDeoptimizationField>( 931cb0ef41Sopenharmony_ci code_kind_specific_flags), 941cb0ef41Sopenharmony_ci &heal_optimized_code_slot); 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_ci // Optimized code is good, get it into the closure and link the closure into 971cb0ef41Sopenharmony_ci // the optimized functions list, then tail call the optimized code. 981cb0ef41Sopenharmony_ci StoreObjectField(function, JSFunction::kCodeOffset, optimized_code); 991cb0ef41Sopenharmony_ci Comment("MaybeTailCallOptimizedCodeSlot:: GenerateTailCallToJSCode"); 1001cb0ef41Sopenharmony_ci GenerateTailCallToJSCode(optimized_code, function); 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci // Optimized code slot contains deoptimized code, or the code is cleared 1031cb0ef41Sopenharmony_ci // and tiering state hasn't yet been updated. Evict the code, update the 1041cb0ef41Sopenharmony_ci // state and re-enter the closure's code. 1051cb0ef41Sopenharmony_ci BIND(&heal_optimized_code_slot); 1061cb0ef41Sopenharmony_ci GenerateTailCallToReturnedCode(Runtime::kHealOptimizedCodeSlot, function); 1071cb0ef41Sopenharmony_ci } 1081cb0ef41Sopenharmony_ci 1091cb0ef41Sopenharmony_ci // Fall-through if the optimized code cell is clear and the tiering state is 1101cb0ef41Sopenharmony_ci // kNone. 1111cb0ef41Sopenharmony_ci BIND(&fallthrough); 1121cb0ef41Sopenharmony_ci} 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_civoid LazyBuiltinsAssembler::CompileLazy(TNode<JSFunction> function) { 1151cb0ef41Sopenharmony_ci // First lookup code, maybe we don't need to compile! 1161cb0ef41Sopenharmony_ci Label compile_function(this, Label::kDeferred); 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_ci // Check the code object for the SFI. If SFI's code entry points to 1191cb0ef41Sopenharmony_ci // CompileLazy, then we need to lazy compile regardless of the function or 1201cb0ef41Sopenharmony_ci // tiering state. 1211cb0ef41Sopenharmony_ci TNode<SharedFunctionInfo> shared = 1221cb0ef41Sopenharmony_ci CAST(LoadObjectField(function, JSFunction::kSharedFunctionInfoOffset)); 1231cb0ef41Sopenharmony_ci TVARIABLE(Uint16T, sfi_data_type); 1241cb0ef41Sopenharmony_ci TNode<CodeT> sfi_code = 1251cb0ef41Sopenharmony_ci GetSharedFunctionInfoCode(shared, &sfi_data_type, &compile_function); 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_ci TNode<HeapObject> feedback_cell_value = LoadFeedbackCellValue(function); 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ci // If feedback cell isn't initialized, compile function 1301cb0ef41Sopenharmony_ci GotoIf(IsUndefined(feedback_cell_value), &compile_function); 1311cb0ef41Sopenharmony_ci 1321cb0ef41Sopenharmony_ci CSA_DCHECK(this, TaggedNotEqual(sfi_code, HeapConstant(BUILTIN_CODE( 1331cb0ef41Sopenharmony_ci isolate(), CompileLazy)))); 1341cb0ef41Sopenharmony_ci StoreObjectField(function, JSFunction::kCodeOffset, sfi_code); 1351cb0ef41Sopenharmony_ci 1361cb0ef41Sopenharmony_ci Label maybe_use_sfi_code(this); 1371cb0ef41Sopenharmony_ci // If there is no feedback, don't check for optimized code. 1381cb0ef41Sopenharmony_ci GotoIf(HasInstanceType(feedback_cell_value, CLOSURE_FEEDBACK_CELL_ARRAY_TYPE), 1391cb0ef41Sopenharmony_ci &maybe_use_sfi_code); 1401cb0ef41Sopenharmony_ci 1411cb0ef41Sopenharmony_ci // If it isn't undefined or fixed array it must be a feedback vector. 1421cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsFeedbackVector(feedback_cell_value)); 1431cb0ef41Sopenharmony_ci 1441cb0ef41Sopenharmony_ci // Is there a tiering state or optimized code in the feedback vector? 1451cb0ef41Sopenharmony_ci MaybeTailCallOptimizedCodeSlot(function, CAST(feedback_cell_value)); 1461cb0ef41Sopenharmony_ci Goto(&maybe_use_sfi_code); 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_ci // At this point we have a candidate Code object. It's *not* a cached 1491cb0ef41Sopenharmony_ci // optimized Code object (we'd have tail-called it above). A usual case would 1501cb0ef41Sopenharmony_ci // be the InterpreterEntryTrampoline to start executing existing bytecode. 1511cb0ef41Sopenharmony_ci BIND(&maybe_use_sfi_code); 1521cb0ef41Sopenharmony_ci Label tailcall_code(this), baseline(this); 1531cb0ef41Sopenharmony_ci TVARIABLE(CodeT, code); 1541cb0ef41Sopenharmony_ci 1551cb0ef41Sopenharmony_ci // Check if we have baseline code. 1561cb0ef41Sopenharmony_ci GotoIf(InstanceTypeEqual(sfi_data_type.value(), CODET_TYPE), &baseline); 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_ci code = sfi_code; 1591cb0ef41Sopenharmony_ci Goto(&tailcall_code); 1601cb0ef41Sopenharmony_ci 1611cb0ef41Sopenharmony_ci BIND(&baseline); 1621cb0ef41Sopenharmony_ci // Ensure we have a feedback vector. 1631cb0ef41Sopenharmony_ci code = Select<CodeT>( 1641cb0ef41Sopenharmony_ci IsFeedbackVector(feedback_cell_value), [=]() { return sfi_code; }, 1651cb0ef41Sopenharmony_ci [=]() { 1661cb0ef41Sopenharmony_ci return CAST(CallRuntime(Runtime::kInstallBaselineCode, 1671cb0ef41Sopenharmony_ci Parameter<Context>(Descriptor::kContext), 1681cb0ef41Sopenharmony_ci function)); 1691cb0ef41Sopenharmony_ci }); 1701cb0ef41Sopenharmony_ci Goto(&tailcall_code); 1711cb0ef41Sopenharmony_ci 1721cb0ef41Sopenharmony_ci BIND(&tailcall_code); 1731cb0ef41Sopenharmony_ci GenerateTailCallToJSCode(code.value(), function); 1741cb0ef41Sopenharmony_ci 1751cb0ef41Sopenharmony_ci BIND(&compile_function); 1761cb0ef41Sopenharmony_ci GenerateTailCallToReturnedCode(Runtime::kCompileLazy, function); 1771cb0ef41Sopenharmony_ci} 1781cb0ef41Sopenharmony_ci 1791cb0ef41Sopenharmony_ciTF_BUILTIN(CompileLazy, LazyBuiltinsAssembler) { 1801cb0ef41Sopenharmony_ci auto function = Parameter<JSFunction>(Descriptor::kTarget); 1811cb0ef41Sopenharmony_ci 1821cb0ef41Sopenharmony_ci CompileLazy(function); 1831cb0ef41Sopenharmony_ci} 1841cb0ef41Sopenharmony_ci 1851cb0ef41Sopenharmony_ciTF_BUILTIN(CompileLazyDeoptimizedCode, LazyBuiltinsAssembler) { 1861cb0ef41Sopenharmony_ci auto function = Parameter<JSFunction>(Descriptor::kTarget); 1871cb0ef41Sopenharmony_ci 1881cb0ef41Sopenharmony_ci TNode<CodeT> code = HeapConstant(BUILTIN_CODE(isolate(), CompileLazy)); 1891cb0ef41Sopenharmony_ci // Set the code slot inside the JSFunction to CompileLazy. 1901cb0ef41Sopenharmony_ci StoreObjectField(function, JSFunction::kCodeOffset, code); 1911cb0ef41Sopenharmony_ci GenerateTailCallToJSCode(code, function); 1921cb0ef41Sopenharmony_ci} 1931cb0ef41Sopenharmony_ci 1941cb0ef41Sopenharmony_ci} // namespace internal 1951cb0ef41Sopenharmony_ci} // namespace v8 196