[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-promise-inl.h"
|
||||
#include "src/objects/slots.h"
|
||||
#include "src/snapshot/embedded/embedded-data.h"
|
||||
#include "src/snapshot/snapshot.h"
|
||||
|
||||
#if V8_ENABLE_WEBASSEMBLY
|
||||
@ -1239,9 +1240,9 @@ class DiscardBaselineCodeVisitor : public ThreadVisitor {
|
||||
void VisitThread(Isolate* isolate, ThreadLocalTop* top) override {
|
||||
bool deopt_all = shared_ == SharedFunctionInfo();
|
||||
for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
|
||||
if (!deopt_all && it.frame()->function().shared() != shared_) continue;
|
||||
if (it.frame()->type() == StackFrame::BASELINE) {
|
||||
BaselineFrame* frame = BaselineFrame::cast(it.frame());
|
||||
if (!deopt_all && frame->function().shared() != shared_) continue;
|
||||
int bytecode_offset = frame->GetBytecodeOffset();
|
||||
Address* pc_addr = frame->pc_address();
|
||||
Address advance = BUILTIN_CODE(isolate, InterpreterEnterAtNextBytecode)
|
||||
@ -1249,6 +1250,27 @@ class DiscardBaselineCodeVisitor : public ThreadVisitor {
|
||||
PointerAuthentication::ReplacePC(pc_addr, advance, kSystemPointerSize);
|
||||
InterpretedFrame::cast(it.Reframe())
|
||||
->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