[maglev] Make maglev frames optimized frames

Split off a TurbofanFrame from OptimizedFrame, and make MaglevFrame a
subclass of OptimizedFrame. This allows it to be treated as an optimized
frame by code that is looking at deoptimization data.

Bug: v8:7700
Change-Id: Ia38e0f1c2cd73f054f63be81dff187d9197c1202
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3644798
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80592}
This commit is contained in:
Leszek Swirski 2022-05-17 14:57:14 +02:00 committed by V8 LUCI CQ
parent d98ae36734
commit 1ab43384ca
13 changed files with 83 additions and 73 deletions

View File

@ -1001,7 +1001,7 @@ bool ScopeIterator::SetLocalVariableValue(Handle<String> variable_name,
parameters_and_registers->set(index, *new_value);
} else {
JavaScriptFrame* frame = GetFrame();
if (frame->is_optimized()) return false;
if (!frame->is_unoptimized()) return false;
frame->SetParameterValue(index, *new_value);
}
@ -1022,7 +1022,7 @@ bool ScopeIterator::SetLocalVariableValue(Handle<String> variable_name,
} else {
// Set the variable on the stack.
JavaScriptFrame* frame = GetFrame();
if (frame->is_optimized()) return false;
if (!frame->is_unoptimized()) return false;
frame->SetExpression(index, *new_value);
}

View File

@ -94,9 +94,10 @@ std::vector<wasm_addr_t> WasmModuleDebug::GetCallStack(
switch (frame->type()) {
case StackFrame::JAVA_SCRIPT_BUILTIN_CONTINUATION:
case StackFrame::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH:
case StackFrame::OPTIMIZED:
case StackFrame::INTERPRETED:
case StackFrame::BASELINE:
case StackFrame::MAGLEV:
case StackFrame::TURBOFAN:
case StackFrame::BUILTIN:
case StackFrame::WASM: {
// A standard frame may include many summarized frames, due to inlining.
@ -153,9 +154,10 @@ std::vector<FrameSummary> WasmModuleDebug::FindWasmFrame(
switch (frame->type()) {
case StackFrame::JAVA_SCRIPT_BUILTIN_CONTINUATION:
case StackFrame::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH:
case StackFrame::OPTIMIZED:
case StackFrame::INTERPRETED:
case StackFrame::BASELINE:
case StackFrame::MAGLEV:
case StackFrame::TURBOFAN:
case StackFrame::BUILTIN:
case StackFrame::WASM: {
// A standard frame may include many summarized frames, due to inlining.

View File

@ -259,7 +259,7 @@ class ActivationsFinder : public ThreadVisitor {
// it to replace the current pc on the stack.
void VisitThread(Isolate* isolate, ThreadLocalTop* top) override {
for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) {
if (it.frame()->type() == StackFrame::OPTIMIZED) {
if (it.frame()->is_optimized()) {
Code code = it.frame()->LookupCode();
if (CodeKindCanDeoptimize(code.kind()) &&
code.marked_for_deoptimization()) {
@ -306,8 +306,7 @@ void Deoptimizer::DeoptimizeMarkedCodeForContext(NativeContext native_context) {
// deoptimized due to weak object dependency.
for (StackFrameIterator it(isolate, isolate->thread_local_top()); !it.done();
it.Advance()) {
StackFrame::Type type = it.frame()->type();
if (type == StackFrame::OPTIMIZED) {
if (it.frame()->is_optimized()) {
Code code = it.frame()->LookupCode();
JSFunction function =
static_cast<OptimizedFrame*>(it.frame())->function();
@ -315,7 +314,7 @@ void Deoptimizer::DeoptimizeMarkedCodeForContext(NativeContext native_context) {
SafepointEntry safepoint =
code.GetSafepointEntry(isolate, it.frame()->pc());
// Turbofan deopt is checked when we are patching addresses on stack.
// Deopt is checked when we are patching addresses on stack.
bool safe_if_deopt_triggered = safepoint.has_deoptimization_index();
bool is_builtin_code = code.kind() == CodeKind::BUILTIN;
DCHECK(topmost_optimized_code.is_null() || safe_if_deopt_triggered ||

View File

@ -220,7 +220,10 @@ inline BaselineFrame::BaselineFrame(StackFrameIteratorBase* iterator)
: UnoptimizedFrame(iterator) {}
inline MaglevFrame::MaglevFrame(StackFrameIteratorBase* iterator)
: JavaScriptFrame(iterator) {}
: OptimizedFrame(iterator) {}
inline TurbofanFrame::TurbofanFrame(StackFrameIteratorBase* iterator)
: OptimizedFrame(iterator) {}
inline BuiltinFrame::BuiltinFrame(StackFrameIteratorBase* iterator)
: TypedFrameWithJSLinkage(iterator) {}

View File

@ -237,7 +237,7 @@ int StackTraceFrameIterator::FrameFunctionCount() const {
DCHECK(!done());
if (!iterator_.frame()->is_optimized()) return 1;
std::vector<SharedFunctionInfo> infos;
OptimizedFrame::cast(iterator_.frame())->GetFunctions(&infos);
TurbofanFrame::cast(iterator_.frame())->GetFunctions(&infos);
return static_cast<int>(infos.size());
}
@ -377,7 +377,7 @@ SafeStackFrameIterator::SafeStackFrameIterator(Isolate* isolate, Address pc,
// iterating the stack from this topmost JS frame.
if (fast_c_fp) {
DCHECK_NE(kNullAddress, isolate->isolate_data()->fast_c_call_caller_pc());
type = StackFrame::Type::OPTIMIZED;
type = StackFrame::Type::TURBOFAN;
top_frame_type_ = type;
state.fp = fast_c_fp;
state.sp = sp;
@ -438,14 +438,14 @@ SafeStackFrameIterator::SafeStackFrameIterator(Isolate* isolate, Address pc,
if (!StackFrame::IsTypeMarker(type_or_context_address))
top_context_address_ = type_or_context_address;
} else {
// Mark the frame as OPTIMIZED if we cannot determine its type.
// We chose OPTIMIZED rather than INTERPRETED because it's closer to
// Mark the frame as TURBOFAN if we cannot determine its type.
// We chose TURBOFAN rather than INTERPRETED because it's closer to
// the original value of StackFrame::JAVA_SCRIPT here, in that JAVA_SCRIPT
// referred to full-codegen frames (now removed from the tree), and
// OPTIMIZED refers to turbofan frames, both of which are generated
// TURBOFAN refers to turbofan frames, both of which are generated
// code. INTERPRETED frames refer to bytecode.
// The frame anyways will be skipped.
type = StackFrame::OPTIMIZED;
type = StackFrame::TURBOFAN;
// Top frame is incomplete so we cannot reliably determine its type.
top_frame_type_ = StackFrame::NO_FRAME_TYPE;
}
@ -626,7 +626,7 @@ StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator,
} else if (IsInterpreterFramePc(iterator->isolate(), pc, state)) {
return INTERPRETED;
} else {
return OPTIMIZED;
return TURBOFAN;
}
}
} else {
@ -669,14 +669,15 @@ StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator,
// OptimizedFrame for now (all the builtins with JavaScript
// linkage are actually generated with TurboFan currently, so
// this is sound).
return OPTIMIZED;
return TURBOFAN;
}
return BUILTIN;
case CodeKind::TURBOFAN:
case CodeKind::MAGLEV:
return OPTIMIZED;
case CodeKind::BASELINE:
return Type::BASELINE;
return BASELINE;
case CodeKind::MAGLEV:
return MAGLEV;
case CodeKind::TURBOFAN:
return TURBOFAN;
#if V8_ENABLE_WEBASSEMBLY
case CodeKind::JS_TO_WASM_FUNCTION:
return JS_TO_WASM;
@ -722,13 +723,12 @@ StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator,
case STACK_SWITCH:
#endif // V8_ENABLE_WEBASSEMBLY
return candidate;
case OPTIMIZED:
case INTERPRETED:
// Any other marker value is likely to be a bogus stack frame when being
// called from the profiler (in particular, JavaScript frames, including
// interpreted frames, should never have a StackFrame::Type
// marker). Consider these frames "native".
default:
// Unoptimized and optimized JavaScript frames, including
// interpreted frames, should never have a StackFrame::Type
// marker. If we find one, we're likely being called from the
// profiler in a bogus stack frame.
return NATIVE;
}
}
@ -1129,10 +1129,10 @@ void CommonFrame::IterateCompiledFrame(RootVisitor* v) const {
frame_header_size = WasmFrameConstants::kFixedFrameSizeFromFp;
break;
#endif // V8_ENABLE_WEBASSEMBLY
case OPTIMIZED:
case INTERPRETED:
case BASELINE:
case MAGLEV:
case TURBOFAN:
case BUILTIN:
// These frame types have a context, but they are actually stored
// in the place on the stack that one finds the frame type.
@ -1305,7 +1305,7 @@ Code CommonFrameWithJSLinkage::unchecked_code() const {
return FromCodeT(function().code());
}
int OptimizedFrame::ComputeParametersCount() const {
int TurbofanFrame::ComputeParametersCount() const {
Code code = LookupCode();
if (code.kind() == CodeKind::BUILTIN) {
return static_cast<int>(
@ -1758,7 +1758,7 @@ void OptimizedFrame::Summarize(std::vector<FrameSummary>* frames) const {
DCHECK(frames->empty());
DCHECK(is_optimized());
// Delegate to JS frame in absence of turbofan deoptimization.
// Delegate to JS frame in absence of deoptimization info.
// TODO(turbofan): Revisit once we support deoptimization across the board.
Code code = LookupCode();
if (code.kind() == CodeKind::BUILTIN) {
@ -1835,7 +1835,8 @@ void OptimizedFrame::Summarize(std::vector<FrameSummary>* frames) const {
}
}
int OptimizedFrame::LookupExceptionHandlerInTable(
// TODO(leszeks): Move to OptimizedFrame when/if maglev supports exceptions.
int TurbofanFrame::LookupExceptionHandlerInTable(
int* data, HandlerTable::CatchPrediction* prediction) {
// We cannot perform exception prediction on optimized code. Instead, we need
// to use FrameSummary to find the corresponding code offset in unoptimized
@ -1937,10 +1938,6 @@ int OptimizedFrame::StackSlotOffsetRelativeToFp(int slot_index) {
((slot_index + 1) * kSystemPointerSize);
}
Object OptimizedFrame::StackSlotAt(int index) const {
return Object(Memory<Address>(fp() + StackSlotOffsetRelativeToFp(index)));
}
int UnoptimizedFrame::position() const {
AbstractCode code = AbstractCode::cast(GetBytecodeArray());
int code_offset = GetBytecodeOffset();

View File

@ -110,7 +110,7 @@ class StackHandler {
V(INTERPRETED, InterpretedFrame) \
V(BASELINE, BaselineFrame) \
V(MAGLEV, MaglevFrame) \
V(OPTIMIZED, OptimizedFrame) \
V(TURBOFAN, TurbofanFrame) \
V(STUB, StubFrame) \
V(BUILTIN_CONTINUATION, BuiltinContinuationFrame) \
V(JAVA_SCRIPT_BUILTIN_CONTINUATION, JavaScriptBuiltinContinuationFrame) \
@ -214,7 +214,10 @@ class StackFrame {
bool is_entry() const { return type() == ENTRY; }
bool is_construct_entry() const { return type() == CONSTRUCT_ENTRY; }
bool is_exit() const { return type() == EXIT; }
bool is_optimized() const { return type() == OPTIMIZED; }
bool is_optimized() const {
static_assert(TURBOFAN == MAGLEV + 1);
return base::IsInRange(type(), MAGLEV, TURBOFAN);
}
bool is_unoptimized() const {
static_assert(BASELINE == INTERPRETED + 1);
return base::IsInRange(type(), INTERPRETED, BASELINE);
@ -222,6 +225,7 @@ class StackFrame {
bool is_interpreted() const { return type() == INTERPRETED; }
bool is_baseline() const { return type() == BASELINE; }
bool is_maglev() const { return type() == MAGLEV; }
bool is_turbofan() const { return type() == TURBOFAN; }
#if V8_ENABLE_WEBASSEMBLY
bool is_wasm() const { return this->type() == WASM; }
bool is_c_wasm_entry() const { return type() == C_WASM_ENTRY; }
@ -247,8 +251,8 @@ class StackFrame {
static bool IsJavaScript(Type t) {
static_assert(INTERPRETED + 1 == BASELINE);
static_assert(BASELINE + 1 == MAGLEV);
static_assert(MAGLEV + 1 == OPTIMIZED);
return t >= INTERPRETED && t <= OPTIMIZED;
static_assert(MAGLEV + 1 == TURBOFAN);
return t >= INTERPRETED && t <= TURBOFAN;
}
bool is_java_script() const { return IsJavaScript(type()); }
@ -810,8 +814,6 @@ class StubFrame : public TypedFrame {
class OptimizedFrame : public JavaScriptFrame {
public:
Type type() const override { return OPTIMIZED; }
// GC support.
void Iterate(RootVisitor* v) const override;
@ -822,23 +824,12 @@ class OptimizedFrame : public JavaScriptFrame {
void Summarize(std::vector<FrameSummary>* frames) const override;
// Lookup exception handler for current {pc}, returns -1 if none found.
int LookupExceptionHandlerInTable(
int* data, HandlerTable::CatchPrediction* prediction) override;
DeoptimizationData GetDeoptimizationData(int* deopt_index) const;
int ComputeParametersCount() const override;
static int StackSlotOffsetRelativeToFp(int slot_index);
protected:
inline explicit OptimizedFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
Object StackSlotAt(int index) const;
};
// An unoptimized frame is a JavaScript frame that is executing bytecode. It
@ -935,7 +926,7 @@ class BaselineFrame : public UnoptimizedFrame {
friend class StackFrameIteratorBase;
};
class MaglevFrame : public JavaScriptFrame {
class MaglevFrame : public OptimizedFrame {
public:
Type type() const override { return MAGLEV; }
@ -951,6 +942,25 @@ class MaglevFrame : public JavaScriptFrame {
friend class StackFrameIteratorBase;
};
class TurbofanFrame : public OptimizedFrame {
public:
Type type() const override { return TURBOFAN; }
// Lookup exception handler for current {pc}, returns -1 if none found.
int LookupExceptionHandlerInTable(
int* data, HandlerTable::CatchPrediction* prediction) override;
int ComputeParametersCount() const override;
protected:
inline explicit TurbofanFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
Object StackSlotAt(int index) const;
};
// Builtin frames are built for builtins with JavaScript linkage, such as
// various standard library functions (i.e. Math.asin, Math.floor, etc.).
class BuiltinFrame final : public TypedFrameWithJSLinkage {

View File

@ -1115,7 +1115,7 @@ void VisitStack(Isolate* isolate, Visitor* visitor,
case StackFrame::BUILTIN_EXIT:
case StackFrame::JAVA_SCRIPT_BUILTIN_CONTINUATION:
case StackFrame::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH:
case StackFrame::OPTIMIZED:
case StackFrame::TURBOFAN:
case StackFrame::INTERPRETED:
case StackFrame::BASELINE:
case StackFrame::BUILTIN:
@ -1918,7 +1918,7 @@ Object Isolate::UnwindAndFindHandler() {
CHECK(!catchable_by_js);
CHECK(frame->is_java_script());
if (frame->is_optimized()) {
if (frame->is_turbofan()) {
Code code = frame->LookupCode();
// The debugger triggers lazy deopt for the "to-be-restarted" frame
// immediately when the CDP event arrives while paused.
@ -1939,6 +1939,7 @@ Object Isolate::UnwindAndFindHandler() {
offset, code.constant_pool(), return_sp,
frame->fp(), visited_frames);
}
DCHECK(!frame->is_maglev());
debug()->clear_restart_frame();
Code code = FromCodeT(builtins()->code(Builtin::kRestartFrameTrampoline));
@ -2022,10 +2023,10 @@ Object Isolate::UnwindAndFindHandler() {
}
#endif // V8_ENABLE_WEBASSEMBLY
case StackFrame::OPTIMIZED: {
case StackFrame::TURBOFAN: {
// For optimized frames we perform a lookup in the handler table.
if (!catchable_by_js) break;
OptimizedFrame* js_frame = static_cast<OptimizedFrame*>(frame);
TurbofanFrame* js_frame = static_cast<TurbofanFrame*>(frame);
Code code = frame->LookupCode();
int offset = js_frame->LookupExceptionHandlerInTable(nullptr, nullptr);
if (offset < 0) break;
@ -2035,7 +2036,7 @@ Object Isolate::UnwindAndFindHandler() {
StandardFrameConstants::kFixedFrameSizeAboveFp -
code.stack_slots() * kSystemPointerSize;
// TODO(bmeurer): Turbofanned BUILTIN frames appear as OPTIMIZED,
// TODO(bmeurer): Turbofanned BUILTIN frames appear as TURBOFAN,
// but do not have a code kind of TURBOFAN.
if (CodeKindCanDeoptimize(code.kind()) &&
code.marked_for_deoptimization()) {
@ -2165,7 +2166,7 @@ Object Isolate::UnwindAndFindHandler() {
break;
}
if (frame->is_optimized()) {
if (frame->is_turbofan()) {
// Remove per-frame stored materialized objects.
bool removed = materialized_object_store_->Remove(frame->fp());
USE(removed);
@ -2181,7 +2182,7 @@ Object Isolate::UnwindAndFindHandler() {
namespace {
HandlerTable::CatchPrediction PredictException(JavaScriptFrame* frame) {
HandlerTable::CatchPrediction prediction;
if (frame->is_optimized()) {
if (frame->is_turbofan()) {
if (frame->LookupExceptionHandlerInTable(nullptr, nullptr) > 0) {
// This optimized frame will catch. It's handler table does not include
// exception prediction, and we need to use the corresponding handler
@ -2257,9 +2258,9 @@ Isolate::CatchType Isolate::PredictExceptionCatcher() {
} break;
// For JavaScript frames we perform a lookup in the handler table.
case StackFrame::OPTIMIZED:
case StackFrame::INTERPRETED:
case StackFrame::BASELINE:
case StackFrame::TURBOFAN:
case StackFrame::BUILTIN: {
JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame);
Isolate::CatchType prediction = ToCatchType(PredictException(js_frame));

View File

@ -2407,7 +2407,7 @@ void MarkCompactCollector::ProcessTopOptimizedFrame(ObjectVisitor* visitor,
for (StackFrameIterator it(isolate, isolate->thread_local_top()); !it.done();
it.Advance()) {
if (it.frame()->is_unoptimized()) return;
if (it.frame()->type() == StackFrame::OPTIMIZED) {
if (it.frame()->is_optimized()) {
Code code = it.frame()->LookupCode();
if (!code.CanDeoptAt(isolate, it.frame()->pc())) {
PtrComprCageBase cage_base(isolate);

View File

@ -497,11 +497,10 @@ void Code::Disassemble(const char* name, std::ostream& os, Isolate* isolate,
os << "stack_slots = " << stack_slots() << "\n";
}
os << "compiler = "
<< (is_turbofanned()
? "turbofan"
: is_maglevved()
? "turbofan"
: kind() == CodeKind::BASELINE ? "baseline" : "unknown")
<< (is_turbofanned() ? "turbofan"
: is_maglevved() ? "maglev"
: kind() == CodeKind::BASELINE ? "baseline"
: "unknown")
<< "\n";
os << "address = " << reinterpret_cast<void*>(ptr()) << "\n\n";

View File

@ -143,9 +143,8 @@ ShouldThrow GetShouldThrow(Isolate* isolate, Maybe<ShouldThrow> should_throw) {
if (mode == LanguageMode::kStrict) return kThrowOnError;
for (StackFrameIterator it(isolate); !it.done(); it.Advance()) {
if (!(it.frame()->is_optimized() || it.frame()->is_unoptimized())) {
continue;
}
if (!it.frame()->is_java_script()) continue;
// Get the language mode from closure.
JavaScriptFrame* js_frame = static_cast<JavaScriptFrame*>(it.frame());
std::vector<SharedFunctionInfo> functions;

View File

@ -782,7 +782,7 @@ RUNTIME_FUNCTION(Runtime_GetOptimizationStatus) {
}
if (frame != nullptr) {
status |= static_cast<int>(OptimizationStatus::kIsExecuting);
if (frame->is_optimized()) {
if (frame->is_turbofan()) {
status |=
static_cast<int>(OptimizationStatus::kTopmostFrameIsTurboFanned);
} else if (frame->is_interpreted()) {

View File

@ -14,7 +14,7 @@ namespace compiler {
static void IsOptimized(const v8::FunctionCallbackInfo<v8::Value>& args) {
JavaScriptFrameIterator it(CcTest::i_isolate());
JavaScriptFrame* frame = it.frame();
return args.GetReturnValue().Set(frame->is_optimized());
return args.GetReturnValue().Set(frame->is_turbofan());
}

View File

@ -585,7 +585,7 @@ FRAME_MARKERS = (
"INTERPRETED",
"BASELINE",
"MAGLEV",
"OPTIMIZED",
"TURBOFAN",
"STUB",
"BUILTIN_CONTINUATION",
"JAVA_SCRIPT_BUILTIN_CONTINUATION",