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