[sparkplug][debugger] Fix deopt of inlined function in debugger
We could end up in a baseline entry trampoline without having baseline code, because of an unhandled interaction in the debugger (discarding baseline code) and the deoptimizer. Bug: chromium:1199681 Change-Id: Ia33bb4d64903dd989728465b3d83a88b84597a8f Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2843820 Reviewed-by: Toon Verwaest <verwaest@chromium.org> Commit-Queue: Patrick Thier <pthier@chromium.org> Cr-Commit-Position: refs/heads/master@{#74153}
This commit is contained in:
parent
56d956aaed
commit
c560e1f9b8
@ -35,6 +35,7 @@
|
|||||||
#include "src/objects/js-generator-inl.h"
|
#include "src/objects/js-generator-inl.h"
|
||||||
#include "src/objects/js-promise-inl.h"
|
#include "src/objects/js-promise-inl.h"
|
||||||
#include "src/objects/slots.h"
|
#include "src/objects/slots.h"
|
||||||
|
#include "src/snapshot/embedded/embedded-data.h"
|
||||||
#include "src/snapshot/snapshot.h"
|
#include "src/snapshot/snapshot.h"
|
||||||
|
|
||||||
#if V8_ENABLE_WEBASSEMBLY
|
#if V8_ENABLE_WEBASSEMBLY
|
||||||
@ -1239,9 +1240,9 @@ class DiscardBaselineCodeVisitor : public ThreadVisitor {
|
|||||||
void VisitThread(Isolate* isolate, ThreadLocalTop* top) override {
|
void VisitThread(Isolate* isolate, ThreadLocalTop* top) override {
|
||||||
bool deopt_all = shared_ == SharedFunctionInfo();
|
bool deopt_all = shared_ == SharedFunctionInfo();
|
||||||
for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
|
for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
|
||||||
|
if (!deopt_all && it.frame()->function().shared() != shared_) continue;
|
||||||
if (it.frame()->type() == StackFrame::BASELINE) {
|
if (it.frame()->type() == StackFrame::BASELINE) {
|
||||||
BaselineFrame* frame = BaselineFrame::cast(it.frame());
|
BaselineFrame* frame = BaselineFrame::cast(it.frame());
|
||||||
if (!deopt_all && frame->function().shared() != shared_) continue;
|
|
||||||
int bytecode_offset = frame->GetBytecodeOffset();
|
int bytecode_offset = frame->GetBytecodeOffset();
|
||||||
Address* pc_addr = frame->pc_address();
|
Address* pc_addr = frame->pc_address();
|
||||||
Address advance = BUILTIN_CODE(isolate, InterpreterEnterAtNextBytecode)
|
Address advance = BUILTIN_CODE(isolate, InterpreterEnterAtNextBytecode)
|
||||||
@ -1249,6 +1250,27 @@ class DiscardBaselineCodeVisitor : public ThreadVisitor {
|
|||||||
PointerAuthentication::ReplacePC(pc_addr, advance, kSystemPointerSize);
|
PointerAuthentication::ReplacePC(pc_addr, advance, kSystemPointerSize);
|
||||||
InterpretedFrame::cast(it.Reframe())
|
InterpretedFrame::cast(it.Reframe())
|
||||||
->PatchBytecodeOffset(bytecode_offset);
|
->PatchBytecodeOffset(bytecode_offset);
|
||||||
|
} else if (it.frame()->type() == StackFrame::INTERPRETED) {
|
||||||
|
// Check if the PC is a baseline entry trampoline. If it is, replace it
|
||||||
|
// with the corresponding interpreter entry trampoline.
|
||||||
|
// This is the case if a baseline function was inlined into a function
|
||||||
|
// we deoptimized in the debugger and are stepping into it.
|
||||||
|
JavaScriptFrame* frame = it.frame();
|
||||||
|
Address pc = frame->pc();
|
||||||
|
Builtins::Name builtin_index =
|
||||||
|
InstructionStream::TryLookupCode(isolate, pc);
|
||||||
|
if (builtin_index == Builtins::kBaselineEnterAtBytecode ||
|
||||||
|
builtin_index == Builtins::kBaselineEnterAtNextBytecode) {
|
||||||
|
Address* pc_addr = frame->pc_address();
|
||||||
|
Builtins::Name advance =
|
||||||
|
builtin_index == Builtins::kBaselineEnterAtBytecode
|
||||||
|
? Builtins::kInterpreterEnterAtBytecode
|
||||||
|
: Builtins::kInterpreterEnterAtNextBytecode;
|
||||||
|
Address advance_pc =
|
||||||
|
isolate->builtins()->builtin(advance).InstructionStart();
|
||||||
|
PointerAuthentication::ReplacePC(pc_addr, advance_pc,
|
||||||
|
kSystemPointerSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
52
test/debugger/regress/regress-crbug-1199681.js
Normal file
52
test/debugger/regress/regress-crbug-1199681.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// 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: --sparkplug --allow-natives-syntax
|
||||||
|
|
||||||
|
function f() {
|
||||||
|
debugger;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function g() {
|
||||||
|
return f(); // Break
|
||||||
|
}
|
||||||
|
|
||||||
|
function h() {
|
||||||
|
return g();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure FeedbackVector to consider f for inlining.
|
||||||
|
%EnsureFeedbackVectorForFunction(f);
|
||||||
|
%CompileBaseline(g);
|
||||||
|
|
||||||
|
%PrepareFunctionForOptimization(h);
|
||||||
|
h();
|
||||||
|
h();
|
||||||
|
|
||||||
|
var Debug = debug.Debug;
|
||||||
|
var step_count = 0;
|
||||||
|
var exception = null;
|
||||||
|
|
||||||
|
function listener(event, exec_state, event_data, data) {
|
||||||
|
if (event != Debug.DebugEvent.Break) return;
|
||||||
|
try {
|
||||||
|
if (step_count == 0) {
|
||||||
|
exec_state.prepareStep(Debug.StepAction.StepOut);
|
||||||
|
} else {
|
||||||
|
assertTrue(exec_state.frame().sourceLineText().includes('Break'));
|
||||||
|
}
|
||||||
|
step_count++;
|
||||||
|
} catch (e) {
|
||||||
|
exception = e;
|
||||||
|
print(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.setListener(listener);
|
||||||
|
%OptimizeFunctionOnNextCall(h);
|
||||||
|
h();
|
||||||
|
Debug.setListener(null);
|
||||||
|
assertNull(exception);
|
||||||
|
assertEquals(2, step_count);
|
Loading…
Reference in New Issue
Block a user