11cb0ef41Sopenharmony_ci// Copyright 2012 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/execution/tiering-manager.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include "src/base/platform/platform.h"
81cb0ef41Sopenharmony_ci#include "src/baseline/baseline-batch-compiler.h"
91cb0ef41Sopenharmony_ci#include "src/baseline/baseline.h"
101cb0ef41Sopenharmony_ci#include "src/codegen/assembler.h"
111cb0ef41Sopenharmony_ci#include "src/codegen/compilation-cache.h"
121cb0ef41Sopenharmony_ci#include "src/codegen/compiler.h"
131cb0ef41Sopenharmony_ci#include "src/codegen/pending-optimization-table.h"
141cb0ef41Sopenharmony_ci#include "src/diagnostics/code-tracer.h"
151cb0ef41Sopenharmony_ci#include "src/execution/execution.h"
161cb0ef41Sopenharmony_ci#include "src/execution/frames-inl.h"
171cb0ef41Sopenharmony_ci#include "src/handles/global-handles.h"
181cb0ef41Sopenharmony_ci#include "src/init/bootstrapper.h"
191cb0ef41Sopenharmony_ci#include "src/interpreter/interpreter.h"
201cb0ef41Sopenharmony_ci#include "src/objects/code.h"
211cb0ef41Sopenharmony_ci#include "src/tracing/trace-event.h"
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_cinamespace v8 {
241cb0ef41Sopenharmony_cinamespace internal {
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ci// Maximum size in bytes of generate code for a function to allow OSR.
271cb0ef41Sopenharmony_cistatic const int kOSRBytecodeSizeAllowanceBase = 119;
281cb0ef41Sopenharmony_cistatic const int kOSRBytecodeSizeAllowancePerTick = 44;
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci#define OPTIMIZATION_REASON_LIST(V)   \
311cb0ef41Sopenharmony_ci  V(DoNotOptimize, "do not optimize") \
321cb0ef41Sopenharmony_ci  V(HotAndStable, "hot and stable")   \
331cb0ef41Sopenharmony_ci  V(SmallFunction, "small function")
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_cienum class OptimizationReason : uint8_t {
361cb0ef41Sopenharmony_ci#define OPTIMIZATION_REASON_CONSTANTS(Constant, message) k##Constant,
371cb0ef41Sopenharmony_ci  OPTIMIZATION_REASON_LIST(OPTIMIZATION_REASON_CONSTANTS)
381cb0ef41Sopenharmony_ci#undef OPTIMIZATION_REASON_CONSTANTS
391cb0ef41Sopenharmony_ci};
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_cichar const* OptimizationReasonToString(OptimizationReason reason) {
421cb0ef41Sopenharmony_ci  static char const* reasons[] = {
431cb0ef41Sopenharmony_ci#define OPTIMIZATION_REASON_TEXTS(Constant, message) message,
441cb0ef41Sopenharmony_ci      OPTIMIZATION_REASON_LIST(OPTIMIZATION_REASON_TEXTS)
451cb0ef41Sopenharmony_ci#undef OPTIMIZATION_REASON_TEXTS
461cb0ef41Sopenharmony_ci  };
471cb0ef41Sopenharmony_ci  size_t const index = static_cast<size_t>(reason);
481cb0ef41Sopenharmony_ci  DCHECK_LT(index, arraysize(reasons));
491cb0ef41Sopenharmony_ci  return reasons[index];
501cb0ef41Sopenharmony_ci}
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci#undef OPTIMIZATION_REASON_LIST
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_cistd::ostream& operator<<(std::ostream& os, OptimizationReason reason) {
551cb0ef41Sopenharmony_ci  return os << OptimizationReasonToString(reason);
561cb0ef41Sopenharmony_ci}
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ciclass OptimizationDecision {
591cb0ef41Sopenharmony_ci public:
601cb0ef41Sopenharmony_ci  static constexpr OptimizationDecision Maglev() {
611cb0ef41Sopenharmony_ci    // TODO(v8:7700): Consider using another reason here.
621cb0ef41Sopenharmony_ci    return {OptimizationReason::kHotAndStable, CodeKind::MAGLEV,
631cb0ef41Sopenharmony_ci            ConcurrencyMode::kConcurrent};
641cb0ef41Sopenharmony_ci  }
651cb0ef41Sopenharmony_ci  static constexpr OptimizationDecision TurbofanHotAndStable() {
661cb0ef41Sopenharmony_ci    return {OptimizationReason::kHotAndStable, CodeKind::TURBOFAN,
671cb0ef41Sopenharmony_ci            ConcurrencyMode::kConcurrent};
681cb0ef41Sopenharmony_ci  }
691cb0ef41Sopenharmony_ci  static constexpr OptimizationDecision TurbofanSmallFunction() {
701cb0ef41Sopenharmony_ci    return {OptimizationReason::kSmallFunction, CodeKind::TURBOFAN,
711cb0ef41Sopenharmony_ci            ConcurrencyMode::kConcurrent};
721cb0ef41Sopenharmony_ci  }
731cb0ef41Sopenharmony_ci  static constexpr OptimizationDecision DoNotOptimize() {
741cb0ef41Sopenharmony_ci    return {OptimizationReason::kDoNotOptimize,
751cb0ef41Sopenharmony_ci            // These values don't matter but we have to pass something.
761cb0ef41Sopenharmony_ci            CodeKind::TURBOFAN, ConcurrencyMode::kConcurrent};
771cb0ef41Sopenharmony_ci  }
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci  constexpr bool should_optimize() const {
801cb0ef41Sopenharmony_ci    return optimization_reason != OptimizationReason::kDoNotOptimize;
811cb0ef41Sopenharmony_ci  }
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci  OptimizationReason optimization_reason;
841cb0ef41Sopenharmony_ci  CodeKind code_kind;
851cb0ef41Sopenharmony_ci  ConcurrencyMode concurrency_mode;
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci private:
881cb0ef41Sopenharmony_ci  OptimizationDecision() = default;
891cb0ef41Sopenharmony_ci  constexpr OptimizationDecision(OptimizationReason optimization_reason,
901cb0ef41Sopenharmony_ci                                 CodeKind code_kind,
911cb0ef41Sopenharmony_ci                                 ConcurrencyMode concurrency_mode)
921cb0ef41Sopenharmony_ci      : optimization_reason(optimization_reason),
931cb0ef41Sopenharmony_ci        code_kind(code_kind),
941cb0ef41Sopenharmony_ci        concurrency_mode(concurrency_mode) {}
951cb0ef41Sopenharmony_ci};
961cb0ef41Sopenharmony_ci// Since we pass by value:
971cb0ef41Sopenharmony_ciSTATIC_ASSERT(sizeof(OptimizationDecision) <= kInt32Size);
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_cinamespace {
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_civoid TraceInOptimizationQueue(JSFunction function) {
1021cb0ef41Sopenharmony_ci  if (FLAG_trace_opt_verbose) {
1031cb0ef41Sopenharmony_ci    PrintF("[not marking function %s for optimization: already queued]\n",
1041cb0ef41Sopenharmony_ci           function.DebugNameCStr().get());
1051cb0ef41Sopenharmony_ci  }
1061cb0ef41Sopenharmony_ci}
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_civoid TraceHeuristicOptimizationDisallowed(JSFunction function) {
1091cb0ef41Sopenharmony_ci  if (FLAG_trace_opt_verbose) {
1101cb0ef41Sopenharmony_ci    PrintF(
1111cb0ef41Sopenharmony_ci        "[not marking function %s for optimization: marked with "
1121cb0ef41Sopenharmony_ci        "%%PrepareFunctionForOptimization for manual optimization]\n",
1131cb0ef41Sopenharmony_ci        function.DebugNameCStr().get());
1141cb0ef41Sopenharmony_ci  }
1151cb0ef41Sopenharmony_ci}
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_civoid TraceRecompile(Isolate* isolate, JSFunction function,
1181cb0ef41Sopenharmony_ci                    OptimizationDecision d) {
1191cb0ef41Sopenharmony_ci  if (FLAG_trace_opt) {
1201cb0ef41Sopenharmony_ci    CodeTracer::Scope scope(isolate->GetCodeTracer());
1211cb0ef41Sopenharmony_ci    PrintF(scope.file(), "[marking ");
1221cb0ef41Sopenharmony_ci    function.ShortPrint(scope.file());
1231cb0ef41Sopenharmony_ci    PrintF(scope.file(), " for optimization to %s, %s, reason: %s",
1241cb0ef41Sopenharmony_ci           CodeKindToString(d.code_kind), ToString(d.concurrency_mode),
1251cb0ef41Sopenharmony_ci           OptimizationReasonToString(d.optimization_reason));
1261cb0ef41Sopenharmony_ci    PrintF(scope.file(), "]\n");
1271cb0ef41Sopenharmony_ci  }
1281cb0ef41Sopenharmony_ci}
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_ci}  // namespace
1311cb0ef41Sopenharmony_ci
1321cb0ef41Sopenharmony_civoid TraceManualRecompile(JSFunction function, CodeKind code_kind,
1331cb0ef41Sopenharmony_ci                          ConcurrencyMode concurrency_mode) {
1341cb0ef41Sopenharmony_ci  if (FLAG_trace_opt) {
1351cb0ef41Sopenharmony_ci    PrintF("[manually marking ");
1361cb0ef41Sopenharmony_ci    function.ShortPrint();
1371cb0ef41Sopenharmony_ci    PrintF(" for optimization to %s, %s]\n", CodeKindToString(code_kind),
1381cb0ef41Sopenharmony_ci           ToString(concurrency_mode));
1391cb0ef41Sopenharmony_ci  }
1401cb0ef41Sopenharmony_ci}
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_civoid TieringManager::Optimize(JSFunction function, CodeKind code_kind,
1431cb0ef41Sopenharmony_ci                              OptimizationDecision d) {
1441cb0ef41Sopenharmony_ci  DCHECK(d.should_optimize());
1451cb0ef41Sopenharmony_ci  TraceRecompile(isolate_, function, d);
1461cb0ef41Sopenharmony_ci  function.MarkForOptimization(isolate_, d.code_kind, d.concurrency_mode);
1471cb0ef41Sopenharmony_ci}
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_cinamespace {
1501cb0ef41Sopenharmony_ci
1511cb0ef41Sopenharmony_cibool HaveCachedOSRCodeForCurrentBytecodeOffset(UnoptimizedFrame* frame,
1521cb0ef41Sopenharmony_ci                                               int* osr_urgency_out) {
1531cb0ef41Sopenharmony_ci  JSFunction function = frame->function();
1541cb0ef41Sopenharmony_ci  const int current_offset = frame->GetBytecodeOffset();
1551cb0ef41Sopenharmony_ci  OSROptimizedCodeCache cache = function.native_context().osr_code_cache();
1561cb0ef41Sopenharmony_ci  interpreter::BytecodeArrayIterator iterator(
1571cb0ef41Sopenharmony_ci      handle(frame->GetBytecodeArray(), frame->isolate()));
1581cb0ef41Sopenharmony_ci  for (BytecodeOffset osr_offset : cache.OsrOffsetsFor(function.shared())) {
1591cb0ef41Sopenharmony_ci    DCHECK(!osr_offset.IsNone());
1601cb0ef41Sopenharmony_ci    iterator.SetOffset(osr_offset.ToInt());
1611cb0ef41Sopenharmony_ci    if (base::IsInRange(current_offset, iterator.GetJumpTargetOffset(),
1621cb0ef41Sopenharmony_ci                        osr_offset.ToInt())) {
1631cb0ef41Sopenharmony_ci      int loop_depth = iterator.GetImmediateOperand(1);
1641cb0ef41Sopenharmony_ci      // `+ 1` because osr_urgency is an exclusive upper limit on the depth.
1651cb0ef41Sopenharmony_ci      *osr_urgency_out = loop_depth + 1;
1661cb0ef41Sopenharmony_ci      return true;
1671cb0ef41Sopenharmony_ci    }
1681cb0ef41Sopenharmony_ci  }
1691cb0ef41Sopenharmony_ci  return false;
1701cb0ef41Sopenharmony_ci}
1711cb0ef41Sopenharmony_ci
1721cb0ef41Sopenharmony_ci}  // namespace
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_cinamespace {
1751cb0ef41Sopenharmony_ci
1761cb0ef41Sopenharmony_cibool TiersUpToMaglev(CodeKind code_kind) {
1771cb0ef41Sopenharmony_ci  // TODO(v8:7700): Flip the UNLIKELY when appropriate.
1781cb0ef41Sopenharmony_ci  return V8_UNLIKELY(FLAG_maglev) && CodeKindIsUnoptimizedJSFunction(code_kind);
1791cb0ef41Sopenharmony_ci}
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_cibool TiersUpToMaglev(base::Optional<CodeKind> code_kind) {
1821cb0ef41Sopenharmony_ci  return code_kind.has_value() && TiersUpToMaglev(code_kind.value());
1831cb0ef41Sopenharmony_ci}
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_ci}  // namespace
1861cb0ef41Sopenharmony_ci
1871cb0ef41Sopenharmony_ci// static
1881cb0ef41Sopenharmony_ciint TieringManager::InterruptBudgetFor(Isolate* isolate, JSFunction function) {
1891cb0ef41Sopenharmony_ci  if (function.has_feedback_vector()) {
1901cb0ef41Sopenharmony_ci    return TiersUpToMaglev(function.GetActiveTier())
1911cb0ef41Sopenharmony_ci               ? FLAG_interrupt_budget_for_maglev
1921cb0ef41Sopenharmony_ci               : FLAG_interrupt_budget;
1931cb0ef41Sopenharmony_ci  }
1941cb0ef41Sopenharmony_ci
1951cb0ef41Sopenharmony_ci  DCHECK(!function.has_feedback_vector());
1961cb0ef41Sopenharmony_ci  DCHECK(function.shared().is_compiled());
1971cb0ef41Sopenharmony_ci  return function.shared().GetBytecodeArray(isolate).length() *
1981cb0ef41Sopenharmony_ci         FLAG_interrupt_budget_factor_for_feedback_allocation;
1991cb0ef41Sopenharmony_ci}
2001cb0ef41Sopenharmony_ci
2011cb0ef41Sopenharmony_ci// static
2021cb0ef41Sopenharmony_ciint TieringManager::InitialInterruptBudget() {
2031cb0ef41Sopenharmony_ci  return V8_LIKELY(FLAG_lazy_feedback_allocation)
2041cb0ef41Sopenharmony_ci             ? FLAG_interrupt_budget_for_feedback_allocation
2051cb0ef41Sopenharmony_ci             : FLAG_interrupt_budget;
2061cb0ef41Sopenharmony_ci}
2071cb0ef41Sopenharmony_ci
2081cb0ef41Sopenharmony_cinamespace {
2091cb0ef41Sopenharmony_ci
2101cb0ef41Sopenharmony_cibool SmallEnoughForOSR(Isolate* isolate, JSFunction function) {
2111cb0ef41Sopenharmony_ci  return function.shared().GetBytecodeArray(isolate).length() <=
2121cb0ef41Sopenharmony_ci         kOSRBytecodeSizeAllowanceBase +
2131cb0ef41Sopenharmony_ci             function.feedback_vector().profiler_ticks() *
2141cb0ef41Sopenharmony_ci                 kOSRBytecodeSizeAllowancePerTick;
2151cb0ef41Sopenharmony_ci}
2161cb0ef41Sopenharmony_ci
2171cb0ef41Sopenharmony_civoid TrySetOsrUrgency(Isolate* isolate, JSFunction function, int osr_urgency) {
2181cb0ef41Sopenharmony_ci  SharedFunctionInfo shared = function.shared();
2191cb0ef41Sopenharmony_ci
2201cb0ef41Sopenharmony_ci  if (V8_UNLIKELY(!FLAG_use_osr)) return;
2211cb0ef41Sopenharmony_ci  if (V8_UNLIKELY(!shared.IsUserJavaScript())) return;
2221cb0ef41Sopenharmony_ci  if (V8_UNLIKELY(shared.optimization_disabled())) return;
2231cb0ef41Sopenharmony_ci
2241cb0ef41Sopenharmony_ci  // We've passed all checks - bump the OSR urgency.
2251cb0ef41Sopenharmony_ci
2261cb0ef41Sopenharmony_ci  BytecodeArray bytecode = shared.GetBytecodeArray(isolate);
2271cb0ef41Sopenharmony_ci  if (V8_UNLIKELY(FLAG_trace_osr)) {
2281cb0ef41Sopenharmony_ci    CodeTracer::Scope scope(isolate->GetCodeTracer());
2291cb0ef41Sopenharmony_ci    PrintF(scope.file(),
2301cb0ef41Sopenharmony_ci           "[OSR - setting osr urgency. function: %s, old urgency: %d, new "
2311cb0ef41Sopenharmony_ci           "urgency: %d]\n",
2321cb0ef41Sopenharmony_ci           function.DebugNameCStr().get(), bytecode.osr_urgency(), osr_urgency);
2331cb0ef41Sopenharmony_ci  }
2341cb0ef41Sopenharmony_ci
2351cb0ef41Sopenharmony_ci  DCHECK_GE(osr_urgency, bytecode.osr_urgency());  // Never lower urgency here.
2361cb0ef41Sopenharmony_ci  bytecode.set_osr_urgency(osr_urgency);
2371cb0ef41Sopenharmony_ci}
2381cb0ef41Sopenharmony_ci
2391cb0ef41Sopenharmony_civoid TryIncrementOsrUrgency(Isolate* isolate, JSFunction function) {
2401cb0ef41Sopenharmony_ci  int old_urgency = function.shared().GetBytecodeArray(isolate).osr_urgency();
2411cb0ef41Sopenharmony_ci  int new_urgency = std::min(old_urgency + 1, BytecodeArray::kMaxOsrUrgency);
2421cb0ef41Sopenharmony_ci  TrySetOsrUrgency(isolate, function, new_urgency);
2431cb0ef41Sopenharmony_ci}
2441cb0ef41Sopenharmony_ci
2451cb0ef41Sopenharmony_civoid TryRequestOsrAtNextOpportunity(Isolate* isolate, JSFunction function) {
2461cb0ef41Sopenharmony_ci  TrySetOsrUrgency(isolate, function, BytecodeArray::kMaxOsrUrgency);
2471cb0ef41Sopenharmony_ci}
2481cb0ef41Sopenharmony_ci
2491cb0ef41Sopenharmony_civoid TryRequestOsrForCachedOsrCode(Isolate* isolate, JSFunction function,
2501cb0ef41Sopenharmony_ci                                   int osr_urgency_for_cached_osr_code) {
2511cb0ef41Sopenharmony_ci  DCHECK_LE(osr_urgency_for_cached_osr_code, BytecodeArray::kMaxOsrUrgency);
2521cb0ef41Sopenharmony_ci  int old_urgency = function.shared().GetBytecodeArray(isolate).osr_urgency();
2531cb0ef41Sopenharmony_ci  // Make sure not to decrease the existing urgency.
2541cb0ef41Sopenharmony_ci  int new_urgency = std::max(old_urgency, osr_urgency_for_cached_osr_code);
2551cb0ef41Sopenharmony_ci  TrySetOsrUrgency(isolate, function, new_urgency);
2561cb0ef41Sopenharmony_ci}
2571cb0ef41Sopenharmony_ci
2581cb0ef41Sopenharmony_cibool ShouldOptimizeAsSmallFunction(int bytecode_size, bool any_ic_changed) {
2591cb0ef41Sopenharmony_ci  return !any_ic_changed &&
2601cb0ef41Sopenharmony_ci         bytecode_size < FLAG_max_bytecode_size_for_early_opt;
2611cb0ef41Sopenharmony_ci}
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_ci}  // namespace
2641cb0ef41Sopenharmony_ci
2651cb0ef41Sopenharmony_civoid TieringManager::RequestOsrAtNextOpportunity(JSFunction function) {
2661cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
2671cb0ef41Sopenharmony_ci  TryRequestOsrAtNextOpportunity(isolate_, function);
2681cb0ef41Sopenharmony_ci}
2691cb0ef41Sopenharmony_ci
2701cb0ef41Sopenharmony_civoid TieringManager::MaybeOptimizeFrame(JSFunction function,
2711cb0ef41Sopenharmony_ci                                        UnoptimizedFrame* frame,
2721cb0ef41Sopenharmony_ci                                        CodeKind code_kind) {
2731cb0ef41Sopenharmony_ci  const TieringState tiering_state = function.feedback_vector().tiering_state();
2741cb0ef41Sopenharmony_ci  const TieringState osr_tiering_state =
2751cb0ef41Sopenharmony_ci      function.feedback_vector().osr_tiering_state();
2761cb0ef41Sopenharmony_ci  if (V8_UNLIKELY(IsInProgress(tiering_state)) ||
2771cb0ef41Sopenharmony_ci      V8_UNLIKELY(IsInProgress(osr_tiering_state))) {
2781cb0ef41Sopenharmony_ci    // Note: This effectively disables OSR for the function while it is being
2791cb0ef41Sopenharmony_ci    // compiled.
2801cb0ef41Sopenharmony_ci    TraceInOptimizationQueue(function);
2811cb0ef41Sopenharmony_ci    return;
2821cb0ef41Sopenharmony_ci  }
2831cb0ef41Sopenharmony_ci
2841cb0ef41Sopenharmony_ci  if (V8_UNLIKELY(FLAG_testing_d8_test_runner) &&
2851cb0ef41Sopenharmony_ci      !PendingOptimizationTable::IsHeuristicOptimizationAllowed(isolate_,
2861cb0ef41Sopenharmony_ci                                                                function)) {
2871cb0ef41Sopenharmony_ci    TraceHeuristicOptimizationDisallowed(function);
2881cb0ef41Sopenharmony_ci    return;
2891cb0ef41Sopenharmony_ci  }
2901cb0ef41Sopenharmony_ci
2911cb0ef41Sopenharmony_ci  // TODO(v8:7700): Consider splitting this up for Maglev/Turbofan.
2921cb0ef41Sopenharmony_ci  if (V8_UNLIKELY(function.shared().optimization_disabled())) return;
2931cb0ef41Sopenharmony_ci
2941cb0ef41Sopenharmony_ci  if (V8_UNLIKELY(FLAG_always_osr)) {
2951cb0ef41Sopenharmony_ci    TryRequestOsrAtNextOpportunity(isolate_, function);
2961cb0ef41Sopenharmony_ci    // Continue below and do a normal optimized compile as well.
2971cb0ef41Sopenharmony_ci  }
2981cb0ef41Sopenharmony_ci
2991cb0ef41Sopenharmony_ci  // If we have matching cached OSR'd code, request OSR at the next opportunity.
3001cb0ef41Sopenharmony_ci  int osr_urgency_for_cached_osr_code;
3011cb0ef41Sopenharmony_ci  if (HaveCachedOSRCodeForCurrentBytecodeOffset(
3021cb0ef41Sopenharmony_ci          frame, &osr_urgency_for_cached_osr_code)) {
3031cb0ef41Sopenharmony_ci    TryRequestOsrForCachedOsrCode(isolate_, function,
3041cb0ef41Sopenharmony_ci                                  osr_urgency_for_cached_osr_code);
3051cb0ef41Sopenharmony_ci  }
3061cb0ef41Sopenharmony_ci
3071cb0ef41Sopenharmony_ci  const bool is_marked_for_any_optimization =
3081cb0ef41Sopenharmony_ci      (static_cast<uint32_t>(tiering_state) & kNoneOrInProgressMask) != 0;
3091cb0ef41Sopenharmony_ci  if (is_marked_for_any_optimization || function.HasAvailableOptimizedCode()) {
3101cb0ef41Sopenharmony_ci    // OSR kicks in only once we've previously decided to tier up, but we are
3111cb0ef41Sopenharmony_ci    // still in the unoptimized frame (this implies a long-running loop).
3121cb0ef41Sopenharmony_ci    if (SmallEnoughForOSR(isolate_, function)) {
3131cb0ef41Sopenharmony_ci      TryIncrementOsrUrgency(isolate_, function);
3141cb0ef41Sopenharmony_ci    }
3151cb0ef41Sopenharmony_ci
3161cb0ef41Sopenharmony_ci    // Return unconditionally and don't run through the optimization decision
3171cb0ef41Sopenharmony_ci    // again; we've already decided to tier up previously.
3181cb0ef41Sopenharmony_ci    return;
3191cb0ef41Sopenharmony_ci  }
3201cb0ef41Sopenharmony_ci
3211cb0ef41Sopenharmony_ci  DCHECK(!is_marked_for_any_optimization &&
3221cb0ef41Sopenharmony_ci         !function.HasAvailableOptimizedCode());
3231cb0ef41Sopenharmony_ci  OptimizationDecision d = ShouldOptimize(function, code_kind, frame);
3241cb0ef41Sopenharmony_ci  if (d.should_optimize()) Optimize(function, code_kind, d);
3251cb0ef41Sopenharmony_ci}
3261cb0ef41Sopenharmony_ci
3271cb0ef41Sopenharmony_ciOptimizationDecision TieringManager::ShouldOptimize(JSFunction function,
3281cb0ef41Sopenharmony_ci                                                    CodeKind code_kind,
3291cb0ef41Sopenharmony_ci                                                    JavaScriptFrame* frame) {
3301cb0ef41Sopenharmony_ci  DCHECK_EQ(code_kind, function.GetActiveTier().value());
3311cb0ef41Sopenharmony_ci
3321cb0ef41Sopenharmony_ci  if (TiersUpToMaglev(code_kind) &&
3331cb0ef41Sopenharmony_ci      !function.shared(isolate_).maglev_compilation_failed()) {
3341cb0ef41Sopenharmony_ci    return OptimizationDecision::Maglev();
3351cb0ef41Sopenharmony_ci  } else if (code_kind == CodeKind::TURBOFAN) {
3361cb0ef41Sopenharmony_ci    // Already in the top tier.
3371cb0ef41Sopenharmony_ci    return OptimizationDecision::DoNotOptimize();
3381cb0ef41Sopenharmony_ci  }
3391cb0ef41Sopenharmony_ci
3401cb0ef41Sopenharmony_ci  BytecodeArray bytecode = function.shared().GetBytecodeArray(isolate_);
3411cb0ef41Sopenharmony_ci  const int ticks = function.feedback_vector().profiler_ticks();
3421cb0ef41Sopenharmony_ci  const int ticks_for_optimization =
3431cb0ef41Sopenharmony_ci      FLAG_ticks_before_optimization +
3441cb0ef41Sopenharmony_ci      (bytecode.length() / FLAG_bytecode_size_allowance_per_tick);
3451cb0ef41Sopenharmony_ci  if (ticks >= ticks_for_optimization) {
3461cb0ef41Sopenharmony_ci    return OptimizationDecision::TurbofanHotAndStable();
3471cb0ef41Sopenharmony_ci  } else if (ShouldOptimizeAsSmallFunction(bytecode.length(),
3481cb0ef41Sopenharmony_ci                                           any_ic_changed_)) {
3491cb0ef41Sopenharmony_ci    // If no IC was patched since the last tick and this function is very
3501cb0ef41Sopenharmony_ci    // small, optimistically optimize it now.
3511cb0ef41Sopenharmony_ci    return OptimizationDecision::TurbofanSmallFunction();
3521cb0ef41Sopenharmony_ci  } else if (FLAG_trace_opt_verbose) {
3531cb0ef41Sopenharmony_ci    PrintF("[not yet optimizing %s, not enough ticks: %d/%d and ",
3541cb0ef41Sopenharmony_ci           function.DebugNameCStr().get(), ticks, ticks_for_optimization);
3551cb0ef41Sopenharmony_ci    if (any_ic_changed_) {
3561cb0ef41Sopenharmony_ci      PrintF("ICs changed]\n");
3571cb0ef41Sopenharmony_ci    } else {
3581cb0ef41Sopenharmony_ci      PrintF(" too large for small function optimization: %d/%d]\n",
3591cb0ef41Sopenharmony_ci             bytecode.length(), FLAG_max_bytecode_size_for_early_opt);
3601cb0ef41Sopenharmony_ci    }
3611cb0ef41Sopenharmony_ci  }
3621cb0ef41Sopenharmony_ci
3631cb0ef41Sopenharmony_ci  return OptimizationDecision::DoNotOptimize();
3641cb0ef41Sopenharmony_ci}
3651cb0ef41Sopenharmony_ci
3661cb0ef41Sopenharmony_ciTieringManager::OnInterruptTickScope::OnInterruptTickScope(
3671cb0ef41Sopenharmony_ci    TieringManager* profiler)
3681cb0ef41Sopenharmony_ci    : profiler_(profiler) {
3691cb0ef41Sopenharmony_ci  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
3701cb0ef41Sopenharmony_ci               "V8.MarkCandidatesForOptimization");
3711cb0ef41Sopenharmony_ci}
3721cb0ef41Sopenharmony_ci
3731cb0ef41Sopenharmony_ciTieringManager::OnInterruptTickScope::~OnInterruptTickScope() {
3741cb0ef41Sopenharmony_ci  profiler_->any_ic_changed_ = false;
3751cb0ef41Sopenharmony_ci}
3761cb0ef41Sopenharmony_ci
3771cb0ef41Sopenharmony_civoid TieringManager::OnInterruptTick(Handle<JSFunction> function) {
3781cb0ef41Sopenharmony_ci  IsCompiledScope is_compiled_scope(
3791cb0ef41Sopenharmony_ci      function->shared().is_compiled_scope(isolate_));
3801cb0ef41Sopenharmony_ci
3811cb0ef41Sopenharmony_ci  // Remember whether the function had a vector at this point. This is relevant
3821cb0ef41Sopenharmony_ci  // later since the configuration 'Ignition without a vector' can be
3831cb0ef41Sopenharmony_ci  // considered a tier on its own. We begin tiering up to tiers higher than
3841cb0ef41Sopenharmony_ci  // Sparkplug only when reaching this point *with* a feedback vector.
3851cb0ef41Sopenharmony_ci  const bool had_feedback_vector = function->has_feedback_vector();
3861cb0ef41Sopenharmony_ci
3871cb0ef41Sopenharmony_ci  // Ensure that the feedback vector has been allocated, and reset the
3881cb0ef41Sopenharmony_ci  // interrupt budget in preparation for the next tick.
3891cb0ef41Sopenharmony_ci  if (had_feedback_vector) {
3901cb0ef41Sopenharmony_ci    function->SetInterruptBudget(isolate_);
3911cb0ef41Sopenharmony_ci  } else {
3921cb0ef41Sopenharmony_ci    JSFunction::CreateAndAttachFeedbackVector(isolate_, function,
3931cb0ef41Sopenharmony_ci                                              &is_compiled_scope);
3941cb0ef41Sopenharmony_ci    DCHECK(is_compiled_scope.is_compiled());
3951cb0ef41Sopenharmony_ci    // Also initialize the invocation count here. This is only really needed for
3961cb0ef41Sopenharmony_ci    // OSR. When we OSR functions with lazy feedback allocation we want to have
3971cb0ef41Sopenharmony_ci    // a non zero invocation count so we can inline functions.
3981cb0ef41Sopenharmony_ci    function->feedback_vector().set_invocation_count(1, kRelaxedStore);
3991cb0ef41Sopenharmony_ci  }
4001cb0ef41Sopenharmony_ci
4011cb0ef41Sopenharmony_ci  DCHECK(function->has_feedback_vector());
4021cb0ef41Sopenharmony_ci  DCHECK(function->shared().is_compiled());
4031cb0ef41Sopenharmony_ci  DCHECK(function->shared().HasBytecodeArray());
4041cb0ef41Sopenharmony_ci
4051cb0ef41Sopenharmony_ci  // TODO(jgruber): Consider integrating this into a linear tiering system
4061cb0ef41Sopenharmony_ci  // controlled by TieringState in which the order is always
4071cb0ef41Sopenharmony_ci  // Ignition-Sparkplug-Turbofan, and only a single tierup is requested at
4081cb0ef41Sopenharmony_ci  // once.
4091cb0ef41Sopenharmony_ci  // It's unclear whether this is possible and/or makes sense - for example,
4101cb0ef41Sopenharmony_ci  // batching compilation can introduce arbitrary latency between the SP
4111cb0ef41Sopenharmony_ci  // compile request and fulfillment, which doesn't work with strictly linear
4121cb0ef41Sopenharmony_ci  // tiering.
4131cb0ef41Sopenharmony_ci  if (CanCompileWithBaseline(isolate_, function->shared()) &&
4141cb0ef41Sopenharmony_ci      !function->ActiveTierIsBaseline()) {
4151cb0ef41Sopenharmony_ci    if (FLAG_baseline_batch_compilation) {
4161cb0ef41Sopenharmony_ci      isolate_->baseline_batch_compiler()->EnqueueFunction(function);
4171cb0ef41Sopenharmony_ci    } else {
4181cb0ef41Sopenharmony_ci      IsCompiledScope is_compiled_scope(
4191cb0ef41Sopenharmony_ci          function->shared().is_compiled_scope(isolate_));
4201cb0ef41Sopenharmony_ci      Compiler::CompileBaseline(isolate_, function, Compiler::CLEAR_EXCEPTION,
4211cb0ef41Sopenharmony_ci                                &is_compiled_scope);
4221cb0ef41Sopenharmony_ci    }
4231cb0ef41Sopenharmony_ci  }
4241cb0ef41Sopenharmony_ci
4251cb0ef41Sopenharmony_ci  // We only tier up beyond sparkplug if we already had a feedback vector.
4261cb0ef41Sopenharmony_ci  if (!had_feedback_vector) return;
4271cb0ef41Sopenharmony_ci
4281cb0ef41Sopenharmony_ci  // Don't tier up if Turbofan is disabled.
4291cb0ef41Sopenharmony_ci  // TODO(jgruber): Update this for a multi-tier world.
4301cb0ef41Sopenharmony_ci  if (V8_UNLIKELY(!isolate_->use_optimizer())) return;
4311cb0ef41Sopenharmony_ci
4321cb0ef41Sopenharmony_ci  // --- We've decided to proceed for now. ---
4331cb0ef41Sopenharmony_ci
4341cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
4351cb0ef41Sopenharmony_ci  OnInterruptTickScope scope(this);
4361cb0ef41Sopenharmony_ci  JSFunction function_obj = *function;
4371cb0ef41Sopenharmony_ci
4381cb0ef41Sopenharmony_ci  function_obj.feedback_vector().SaturatingIncrementProfilerTicks();
4391cb0ef41Sopenharmony_ci
4401cb0ef41Sopenharmony_ci  JavaScriptFrameIterator it(isolate_);
4411cb0ef41Sopenharmony_ci  UnoptimizedFrame* frame = UnoptimizedFrame::cast(it.frame());
4421cb0ef41Sopenharmony_ci  const CodeKind code_kind = function_obj.GetActiveTier().value();
4431cb0ef41Sopenharmony_ci  MaybeOptimizeFrame(function_obj, frame, code_kind);
4441cb0ef41Sopenharmony_ci}
4451cb0ef41Sopenharmony_ci
4461cb0ef41Sopenharmony_ci}  // namespace internal
4471cb0ef41Sopenharmony_ci}  // namespace v8
448