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