[test][sparkplug] Test Ignition -> Sparkplug OSR

- Add %BaselineOsr to manually trigger OSR to Baseline.
- Add flags to %GetOptimizationStatus to check if the topmost frame is
an Interpreter/Baseline frame.
- Add mjsunit test.

Bug: v8:11420
Change-Id: Id80421ad97ee719a67ef299cc700da9c44f23bae
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2814567
Auto-Submit: Patrick Thier <pthier@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Commit-Queue: Patrick Thier <pthier@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73937}
This commit is contained in:
Patrick Thier 2021-04-13 12:52:09 +00:00 committed by Commit Bot
parent 7de9631d57
commit 5f49bbdf84
9 changed files with 233 additions and 108 deletions

View File

@ -2310,6 +2310,7 @@ v8_header_set("v8_internal_headers") {
"src/baseline/baseline-assembler-inl.h",
"src/baseline/baseline-assembler.h",
"src/baseline/baseline-compiler.h",
"src/baseline/baseline-osr-inl.h",
"src/baseline/baseline.h",
"src/baseline/bytecode-offset-iterator.h",
"src/builtins/accessors.h",

View File

@ -5,6 +5,7 @@ include_rules = [
"+src/asmjs/asm-js.h",
"-src/baseline",
"+src/baseline/baseline.h",
"+src/baseline/baseline-osr-inl.h",
"+src/baseline/bytecode-offset-iterator.h",
"-src/bigint",
"+src/bigint/bigint.h",

View File

@ -0,0 +1,38 @@
// Copyright 2021 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.
//
#ifndef V8_BASELINE_BASELINE_OSR_INL_H_
#define V8_BASELINE_BASELINE_OSR_INL_H_
#include "src/execution/frames.h"
#include "src/execution/isolate-inl.h"
namespace v8 {
namespace internal {
inline void OSRInterpreterFrameToBaseline(Isolate* isolate,
Handle<JSFunction> function,
UnoptimizedFrame* frame) {
IsCompiledScope is_compiled_scope(
function->shared().is_compiled_scope(isolate));
if (Compiler::CompileBaseline(isolate, function, Compiler::CLEAR_EXCEPTION,
&is_compiled_scope)) {
if (V8_LIKELY(FLAG_use_osr)) {
DCHECK_NOT_NULL(frame);
if (FLAG_trace_osr) {
CodeTracer::Scope scope(isolate->GetCodeTracer());
PrintF(scope.file(),
"[OSR - Entry at OSR bytecode offset %d into baseline code]\n",
frame->GetBytecodeOffset());
}
frame->GetBytecodeArray().set_osr_loop_nesting_level(
AbstractCode::kMaxLoopNestingMarker);
}
}
}
} // namespace internal
} // namespace v8
#endif // V8_BASELINE_BASELINE_OSR_INL_H_

View File

@ -7,6 +7,7 @@
#include "src/api/api.h"
#include "src/ast/ast-traversal-visitor.h"
#include "src/ast/prettyprinter.h"
#include "src/baseline/baseline-osr-inl.h"
#include "src/baseline/baseline.h"
#include "src/builtins/builtins.h"
#include "src/common/message-template.h"
@ -342,23 +343,13 @@ RUNTIME_FUNCTION(Runtime_BytecodeBudgetInterruptFromBytecode) {
// a non zero invocation count so we can inline functions.
function->feedback_vector().set_invocation_count(1);
if (FLAG_sparkplug) {
if (Compiler::CompileBaseline(isolate, function,
Compiler::CLEAR_EXCEPTION,
&is_compiled_scope)) {
if (FLAG_use_osr) {
if (V8_LIKELY(FLAG_use_osr)) {
JavaScriptFrameIterator it(isolate);
DCHECK(it.frame()->is_unoptimized());
UnoptimizedFrame* frame = UnoptimizedFrame::cast(it.frame());
if (FLAG_trace_osr) {
CodeTracer::Scope scope(isolate->GetCodeTracer());
PrintF(
scope.file(),
"[OSR - Entry at OSR bytecode offset %d into baseline code]\n",
frame->GetBytecodeOffset());
}
frame->GetBytecodeArray().set_osr_loop_nesting_level(
AbstractCode::kMaxLoopNestingMarker);
}
OSRInterpreterFrameToBaseline(isolate, function, frame);
} else {
OSRInterpreterFrameToBaseline(isolate, function, nullptr);
}
}
return ReadOnlyRoots(isolate).undefined_value();

View File

@ -4,6 +4,7 @@
#include "src/api/api-inl.h"
#include "src/base/platform/mutex.h"
#include "src/baseline/baseline-osr-inl.h"
#include "src/codegen/assembler-inl.h"
#include "src/codegen/compiler.h"
#include "src/codegen/pending-optimization-table.h"
@ -470,6 +471,37 @@ RUNTIME_FUNCTION(Runtime_OptimizeOsr) {
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_BaselineOsr) {
HandleScope scope(isolate);
DCHECK(args.length() == 0 || args.length() == 1);
Handle<JSFunction> function;
// The optional parameter determines the frame being targeted.
int stack_depth = 0;
if (args.length() == 1) {
if (!args[0].IsSmi()) return CrashUnlessFuzzing(isolate);
stack_depth = args.smi_at(0);
}
// Find the JavaScript function on the top of the stack.
JavaScriptFrameIterator it(isolate);
while (!it.done() && stack_depth--) it.Advance();
if (!it.done()) function = handle(it.frame()->function(), isolate);
if (function.is_null()) return CrashUnlessFuzzing(isolate);
if (!FLAG_sparkplug || !FLAG_use_osr) {
return ReadOnlyRoots(isolate).undefined_value();
}
if (!it.frame()->is_unoptimized()) {
return ReadOnlyRoots(isolate).undefined_value();
}
UnoptimizedFrame* frame = UnoptimizedFrame::cast(it.frame());
OSRInterpreterFrameToBaseline(isolate, function, frame);
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
@ -576,6 +608,11 @@ RUNTIME_FUNCTION(Runtime_GetOptimizationStatus) {
if (frame->is_optimized()) {
status |=
static_cast<int>(OptimizationStatus::kTopmostFrameIsTurboFanned);
} else if (frame->is_interpreted()) {
status |=
static_cast<int>(OptimizationStatus::kTopmostFrameIsInterpreted);
} else if (frame->is_baseline()) {
status |= static_cast<int>(OptimizationStatus::kTopmostFrameIsBaseline);
}
}

View File

@ -220,6 +220,7 @@ bool Runtime::IsAllowListedForFuzzing(FunctionId id) {
case Runtime::kIsBeingInterpreted:
return !FLAG_allow_natives_for_differential_fuzzing;
case Runtime::kCompileBaseline:
case Runtime::kBaselineOsr:
return FLAG_sparkplug;
default:
return false;

View File

@ -465,6 +465,7 @@ namespace internal {
F(AbortJS, 1, 1) \
F(AbortCSAAssert, 1, 1) \
F(ArraySpeciesProtector, 0, 1) \
F(BaselineOsr, -1, 1) \
F(ClearFunctionFeedback, 1, 1) \
F(ClearMegamorphicStubCache, 0, 1) \
F(CompleteInobjectSlackTracking, 1, 1) \
@ -862,6 +863,8 @@ enum class OptimizationStatus {
kLiteMode = 1 << 12,
kMarkedForDeoptimization = 1 << 13,
kBaseline = 1 << 14,
kTopmostFrameIsInterpreted = 1 << 15,
kTopmostFrameIsBaseline = 1 << 16,
};
} // namespace internal

View File

@ -0,0 +1,51 @@
// Copyright 2021 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 --sparkplug --no-always-sparkplug --use-osr
// Flags: --opt
function isExecutingBaseline(func) {
let opt_status = %GetOptimizationStatus(func);
return (opt_status & V8OptimizationStatus.kTopmostFrameIsBaseline) !== 0;
}
function f() {
for (var i = 0; i <= 20; i++) {
if (i == 5) {
%BaselineOsr();
}
if (i > 5) {
assertTrue(isBaseline(f));
assertTrue(isExecutingBaseline(f));
}
}
}
%NeverOptimizeFunction(f);
f();
var expectedStatus = V8OptimizationStatus.kTopmostFrameIsInterpreted;
function checkTopmostFrame(func) {
let opt_status = %GetOptimizationStatus(func);
assertTrue ((opt_status & expectedStatus) !== 0, "Expected flag " +
expectedStatus + " to be set in optimization status");
}
function g() {
for (var i = 0; i <= 20; i++) {
checkTopmostFrame(g)
if (i == 2) {
%BaselineOsr();
expectedStatus = V8OptimizationStatus.kTopmostFrameIsBaseline;
}
if (i == 5) {
%OptimizeOsr();
expectedStatus = V8OptimizationStatus.kTopmostFrameIsTurboFanned;
}
}
}
%PrepareFunctionForOptimization(g);
g();

View File

@ -176,6 +176,8 @@ var V8OptimizationStatus = {
kLiteMode: 1 << 12,
kMarkedForDeoptimization: 1 << 13,
kBaseline: 1 << 14,
kTopmostFrameIsInterpreted: 1 << 15,
kTopmostFrameIsBaseline: 1 << 16,
};
// Returns true if --lite-mode is on and we can't ever turn on optimization.