Commit 123c38a5 authored by Jakob Gruber's avatar Jakob Gruber Committed by V8 LUCI CQ

[maglev] Basic tiering to Maglev

When --maglev is set, tier up to Maglev from unoptimized tiers based on
--interrupt-budget-for-maglev, initially set to 40KB (which should very
roughly by 1/10th of the time until the TF tierup decision is made).
On the first interrupt, a non-concurrent optimization to Maglev is
requested, which the next call to the marked function will perform.

- There is no support for tiering from Maglev to TF yet.
- Maglev's language support is minimal and tests are not expected to
  pass with --maglev.
- Disable --maglev by default for now.

Drive-by: fixes related to Maglev flag definitions.

Bug: v8:7700
Change-Id: I121bb3f4f3830fdd20e1d4a12d3e04f08a99be38
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3500302Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79328}
parent 7d4c264e
......@@ -88,6 +88,12 @@ void TraceRecompile(JSFunction function, OptimizationReason reason,
class OptimizationDecision {
public:
static constexpr OptimizationDecision Maglev() {
// TODO(v8:7700): Consider using another reason here.
// TODO(v8:7700): Support concurrency.
return {OptimizationReason::kHotAndStable, CodeKind::MAGLEV,
ConcurrencyMode::kNotConcurrent};
}
static constexpr OptimizationDecision TurbofanHotAndStable() {
return {OptimizationReason::kHotAndStable, CodeKind::TURBOFAN,
ConcurrencyMode::kConcurrent};
......@@ -156,10 +162,25 @@ void TieringManager::AttemptOnStackReplacement(UnoptimizedFrame* frame,
{level + loop_nesting_levels, AbstractCode::kMaxLoopNestingMarker}));
}
namespace {
bool TiersUpToMaglev(CodeKind code_kind) {
// TODO(v8:7700): Flip the UNLIKELY when appropriate.
return V8_UNLIKELY(FLAG_maglev) && CodeKindIsUnoptimizedJSFunction(code_kind);
}
bool TiersUpToMaglev(base::Optional<CodeKind> code_kind) {
return code_kind.has_value() && TiersUpToMaglev(code_kind.value());
}
} // namespace
// static
int TieringManager::InterruptBudgetFor(Isolate* isolate, JSFunction function) {
if (function.has_feedback_vector()) {
return FLAG_interrupt_budget; // For Turbofan.
return TiersUpToMaglev(function.GetActiveTier())
? FLAG_interrupt_budget_for_maglev
: FLAG_interrupt_budget;
}
DCHECK(!function.has_feedback_vector());
......@@ -190,11 +211,11 @@ void TieringManager::MaybeOptimizeFrame(JSFunction function,
return;
}
// TODO(v8:7700): Consider splitting this up for Maglev/Turbofan.
if (function.shared().optimization_disabled()) return;
// Note: We currently do not trigger OSR compilation from TP code.
if (frame->is_unoptimized()) {
if (FLAG_always_osr) {
if (V8_UNLIKELY(FLAG_always_osr)) {
AttemptOnStackReplacement(UnoptimizedFrame::cast(frame),
AbstractCode::kMaxLoopNestingMarker);
// Fall through and do a normal optimized compile as well.
......@@ -236,7 +257,9 @@ OptimizationDecision TieringManager::ShouldOptimize(JSFunction function,
JavaScriptFrame* frame) {
DCHECK_EQ(code_kind, function.GetActiveTier().value());
if (code_kind == CodeKind::TURBOFAN) {
if (TiersUpToMaglev(code_kind)) {
return OptimizationDecision::Maglev();
} else if (code_kind == CodeKind::TURBOFAN) {
// Already in the top tier.
return OptimizationDecision::DoNotOptimize();
}
......
......@@ -515,12 +515,12 @@ DEFINE_BOOL(future, FUTURE_BOOL,
#ifdef V8_ENABLE_MAGLEV
#define V8_ENABLE_MAGLEV_BOOL true
DEFINE_BOOL(maglev, false, "enable the maglev optimizing compiler")
#else
#define V8_ENABLE_MAGLEV_BOOL false
DEFINE_BOOL_READONLY(maglev, false, "enable the maglev optimizing compiler")
#endif // V8_ENABLE_MAGLEV
DEFINE_BOOL(maglev, V8_ENABLE_MAGLEV_BOOL,
"enable the maglev optimizing compiler")
DEFINE_STRING(maglev_filter, "*", "optimization filter for the maglev compiler")
DEFINE_BOOL(maglev_break_on_entry, false, "insert an int3 on maglev entries")
DEFINE_BOOL(print_maglev_graph, false, "print maglev graph")
......@@ -557,9 +557,11 @@ DEFINE_IMPLICATION(jitless, regexp_interpret_all)
// No Sparkplug compilation.
DEFINE_NEG_IMPLICATION(jitless, sparkplug)
DEFINE_NEG_IMPLICATION(jitless, always_sparkplug)
#endif // ENABLE_SPARKPLUG
#ifdef V8_ENABLE_MAGLEV
// No Maglev compilation.
DEFINE_NEG_IMPLICATION(jitless, maglev)
#endif
#endif // V8_ENABLE_MAGLEV
#ifndef V8_TARGET_ARCH_ARM
// Unsupported on arm. See https://crbug.com/v8/8713.
......@@ -628,6 +630,12 @@ DEFINE_INT(interrupt_budget_factor_for_feedback_allocation, 8,
"The interrupt budget factor (applied to bytecode size) for "
"allocating feedback vectors, used when bytecode size is known")
// Tiering: Maglev.
// The Maglev interrupt budget is chosen to be roughly 1/10th of Turbofan's
// overall budget (including the multiple required ticks).
DEFINE_INT(interrupt_budget_for_maglev, 40 * KB,
"interrupt budget which should be used for the profiler counter")
// Tiering: Turbofan.
DEFINE_INT(interrupt_budget, 132 * KB,
"interrupt budget which should be used for the profiler counter")
......
......@@ -16,6 +16,8 @@ namespace internal {
MaybeHandle<CodeT> Maglev::Compile(Isolate* isolate,
Handle<JSFunction> function) {
DCHECK(FLAG_maglev);
CanonicalHandleScope canonical_handle_scope(isolate);
Zone broker_zone(isolate->allocator(), "maglev-broker-zone");
compiler::JSHeapBroker broker(isolate, &broker_zone, FLAG_trace_heap_broker,
......
......@@ -123,10 +123,10 @@ using CodeKinds = base::Flags<CodeKindFlag>;
DEFINE_OPERATORS_FOR_FLAGS(CodeKinds)
static constexpr CodeKinds kJSFunctionCodeKindsMask{
CodeKindFlag::INTERPRETED_FUNCTION | CodeKindFlag::TURBOFAN |
CodeKindFlag::BASELINE};
CodeKindFlag::INTERPRETED_FUNCTION | CodeKindFlag::BASELINE |
CodeKindFlag::MAGLEV | CodeKindFlag::TURBOFAN};
static constexpr CodeKinds kOptimizedJSFunctionCodeKindsMask{
CodeKindFlag::TURBOFAN};
CodeKindFlag::MAGLEV | CodeKindFlag::TURBOFAN};
} // namespace internal
} // namespace v8
......
......@@ -85,18 +85,14 @@ namespace {
V8_WARN_UNUSED_RESULT bool HighestTierOf(CodeKinds kinds,
CodeKind* highest_tier) {
DCHECK_EQ((kinds & ~kJSFunctionCodeKindsMask), 0);
if ((kinds & CodeKindFlag::TURBOFAN) != 0) {
*highest_tier = CodeKind::TURBOFAN;
return true;
} else if ((kinds & CodeKindFlag::BASELINE) != 0) {
*highest_tier = CodeKind::BASELINE;
return true;
} else if ((kinds & CodeKindFlag::INTERPRETED_FUNCTION) != 0) {
*highest_tier = CodeKind::INTERPRETED_FUNCTION;
return true;
}
DCHECK_EQ(kinds, 0);
return false;
// Higher tiers > lower tiers.
STATIC_ASSERT(CodeKind::TURBOFAN > CodeKind::INTERPRETED_FUNCTION);
if (kinds == 0) return false;
const int highest_tier_log2 =
31 - base::bits::CountLeadingZeros(static_cast<uint32_t>(kinds));
DCHECK(CodeKindIsJSFunction(static_cast<CodeKind>(highest_tier_log2)));
*highest_tier = static_cast<CodeKind>(highest_tier_log2);
return true;
}
} // namespace
......@@ -137,10 +133,6 @@ bool JSFunction::ActiveTierIsIgnition() const {
return GetActiveTier() == CodeKind::INTERPRETED_FUNCTION;
}
bool JSFunction::ActiveTierIsTurbofan() const {
return GetActiveTier() == CodeKind::TURBOFAN;
}
bool JSFunction::ActiveTierIsBaseline() const {
return GetActiveTier() == CodeKind::BASELINE;
}
......@@ -149,6 +141,10 @@ bool JSFunction::ActiveTierIsMaglev() const {
return GetActiveTier() == CodeKind::MAGLEV;
}
bool JSFunction::ActiveTierIsTurbofan() const {
return GetActiveTier() == CodeKind::TURBOFAN;
}
bool JSFunction::CanDiscardCompiled() const {
// Essentially, what we are asking here is, has this function been compiled
// from JS code? We can currently tell only indirectly, by looking at
......
......@@ -143,9 +143,9 @@ class JSFunction : public TorqueGeneratedJSFunction<
base::Optional<CodeKind> GetActiveTier() const;
V8_EXPORT_PRIVATE bool ActiveTierIsIgnition() const;
bool ActiveTierIsTurbofan() const;
bool ActiveTierIsBaseline() const;
bool ActiveTierIsMaglev() const;
bool ActiveTierIsTurbofan() const;
// Similar to SharedFunctionInfo::CanDiscardCompiled. Returns true, if the
// attached code can be recreated at a later point by replacing it with
......
......@@ -431,6 +431,13 @@ RUNTIME_FUNCTION(Runtime_BenchMaglev) {
}
#endif // V8_ENABLE_MAGLEV
RUNTIME_FUNCTION(Runtime_ActiveTierIsMaglev) {
HandleScope scope(isolate);
DCHECK_EQ(args.length(), 1);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
return isolate->heap()->ToBoolean(function->ActiveTierIsMaglev());
}
#ifdef V8_ENABLE_MAGLEV
RUNTIME_FUNCTION(Runtime_OptimizeMaglevOnNextCall) {
HandleScope scope(isolate);
......
......@@ -464,6 +464,7 @@ namespace internal {
F(Abort, 1, 1) \
F(AbortCSADcheck, 1, 1) \
F(AbortJS, 1, 1) \
F(ActiveTierIsMaglev, 1, 1) \
F(ArrayIteratorProtector, 0, 1) \
F(ArraySpeciesProtector, 0, 1) \
F(BaselineOsr, -1, 1) \
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax
// Flags: --allow-natives-syntax --maglev
function f(x) {
if (x) return 1;
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax
// Flags: --allow-natives-syntax --maglev
var xyz = 42;
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax
// Flags: --allow-natives-syntax --maglev
function f(x) {
if (x < 0) return -1;
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax
// Flags: --allow-natives-syntax --maglev
function f(x) {
var y = 0;
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax
// Flags: --allow-natives-syntax --maglev
function f(x) {
while (true) {
if (x) return 10;
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax
// Flags: --allow-natives-syntax --maglev
function f(i, end) {
do {
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax
// Flags: --allow-natives-syntax --maglev
function f(i, j) {
var x = 1;
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax
// Flags: --allow-natives-syntax --maglev
function f(i) {
var x = 1;
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax
// Flags: --allow-natives-syntax --maglev
function f(i) {
var x = 1;
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax
// Flags: --allow-natives-syntax --maglev
function f(i) {
var x = 1;
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax
// Flags: --allow-natives-syntax --maglev
const ys = [0,1,2];
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax
// Flags: --allow-natives-syntax --maglev
function f(x) {
return x.a
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax
// Flags: --allow-natives-syntax --maglev
function g() {
%CollectGarbage(42);
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax
// Flags: --allow-natives-syntax --maglev
function f(a) {
while(true) {
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax
// Flags: --allow-natives-syntax --maglev
function f(i) {
a:{
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax
// Flags: --allow-natives-syntax --maglev
var xyz = 42;
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax
// Flags: --allow-natives-syntax --maglev
function f(x) {
return x.a;
......
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --allow-natives-syntax --maglev --no-stress-opt
function f(x) {
var y = 0;
for (var i = 0; i < x; i++) {
y = 1;
}
return y;
}
function g() {
// Test that normal tiering (without OptimizeMaglevOnNextCall) works.
for (let i = 0; i < 1000; i++) {
if (%ActiveTierIsMaglev(f)) break;
f(10);
}
}
%NeverOptimizeFunction(g);
g();
assertTrue(%ActiveTierIsMaglev(f));
......@@ -1344,6 +1344,13 @@
'mjsunit-assertion-error': [SKIP],
}], # no_harness
##############################################################################
['arch != x64 or not pointer_compression or variant in (nooptimization, jitless)', {
# Maglev is x64-only for now.
# TODO(v8:7700): Update as we extend support.
'maglev/*': [SKIP],
}], # arch != x64 or not pointer_compression or variant in (nooptimization, jitless)
##############################################################################
['arch != x64 or deopt_fuzzer', {
# Skip stress-deopt-count tests since it's in x64 only
......
......@@ -50,36 +50,44 @@ ALL_VARIANT_FLAGS = {
# variant. This depends on the flags specified in ALL_VARIANT_FLAGS and on the
# implications defined in flag-definitions.h.
INCOMPATIBLE_FLAGS_PER_VARIANT = {
"jitless": ["--opt", "--always-opt", "--liftoff", "--track-field-types",
"--validate-asm", "--sparkplug", "--concurrent-sparkplug",
"--always-sparkplug", "--regexp-tier-up", "--no-regexp-interpret-all"],
"nooptimization": ["--always-opt"],
"slow_path": ["--no-force-slow-path"],
"stress_concurrent_allocation": ["--single-threaded-gc", "--predictable"],
"stress_concurrent_inlining": ["--single-threaded", "--predictable",
"--lazy-feedback-allocation",
"--assert-types",
"--no-concurrent-recompilation"],
# The fast API tests initialize an embedder object that never needs to be
# serialized to the snapshot, so we don't have a
# SerializeInternalFieldsCallback for it, so they are incompatible with
# stress_snapshot.
"stress_snapshot": ["--expose-fast-api"],
"stress": ["--always-opt", "--no-always-opt",
"--max-inlined-bytecode-size=*",
"--max-inlined-bytecode-size-cumulative=*", "--stress-inline",
"--liftoff-only", "--wasm-speculative-inlining",
"--wasm-dynamic-tiering"],
"sparkplug": ["--jitless"],
"concurrent_sparkplug": ["--jitless"],
"always_sparkplug": ["--jitless"],
"code_serializer": ["--cache=after-execute", "--cache=full-code-cache",
"--cache=none"],
"experimental_regexp": ["--no-enable-experimental-regexp-engine"],
# There is a negative implication: --perf-prof disables
# --wasm-write-protect-code-memory.
"wasm_write_protect_code": ["--perf-prof"],
"assert_types": ["--concurrent-recompilation", "--stress_concurrent_inlining", "--no-assert-types"],
"jitless": [
"--opt", "--always-opt", "--liftoff", "--track-field-types",
"--validate-asm", "--sparkplug", "--concurrent-sparkplug",
"--always-sparkplug", "--regexp-tier-up", "--no-regexp-interpret-all",
"--maglev"
],
"nooptimization": ["--always-opt"],
"slow_path": ["--no-force-slow-path"],
"stress_concurrent_allocation": ["--single-threaded-gc", "--predictable"],
"stress_concurrent_inlining": [
"--single-threaded", "--predictable", "--lazy-feedback-allocation",
"--assert-types", "--no-concurrent-recompilation"
],
# The fast API tests initialize an embedder object that never needs to be
# serialized to the snapshot, so we don't have a
# SerializeInternalFieldsCallback for it, so they are incompatible with
# stress_snapshot.
"stress_snapshot": ["--expose-fast-api"],
"stress": [
"--always-opt", "--no-always-opt", "--max-inlined-bytecode-size=*",
"--max-inlined-bytecode-size-cumulative=*", "--stress-inline",
"--liftoff-only", "--wasm-speculative-inlining",
"--wasm-dynamic-tiering"
],
"sparkplug": ["--jitless"],
"concurrent_sparkplug": ["--jitless"],
"always_sparkplug": ["--jitless"],
"code_serializer": [
"--cache=after-execute", "--cache=full-code-cache", "--cache=none"
],
"experimental_regexp": ["--no-enable-experimental-regexp-engine"],
# There is a negative implication: --perf-prof disables
# --wasm-write-protect-code-memory.
"wasm_write_protect_code": ["--perf-prof"],
"assert_types": [
"--concurrent-recompilation", "--stress_concurrent_inlining",
"--no-assert-types"
],
}
# Flags that lead to a contradiction under certain build variables.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment