Skip to content

Commit c560e1f

Browse files
Patrick ThierCommit Bot
authored andcommitted
[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 <[email protected]> Commit-Queue: Patrick Thier <[email protected]> Cr-Commit-Position: refs/heads/master@{#74153}
1 parent 56d956a commit c560e1f

File tree

2 files changed

+75
-1
lines changed

2 files changed

+75
-1
lines changed

src/debug/debug.cc

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "src/objects/js-generator-inl.h"
3636
#include "src/objects/js-promise-inl.h"
3737
#include "src/objects/slots.h"
38+
#include "src/snapshot/embedded/embedded-data.h"
3839
#include "src/snapshot/snapshot.h"
3940

4041
#if V8_ENABLE_WEBASSEMBLY
@@ -1239,16 +1240,37 @@ class DiscardBaselineCodeVisitor : public ThreadVisitor {
12391240
void VisitThread(Isolate* isolate, ThreadLocalTop* top) override {
12401241
bool deopt_all = shared_ == SharedFunctionInfo();
12411242
for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
1243+
if (!deopt_all && it.frame()->function().shared() != shared_) continue;
12421244
if (it.frame()->type() == StackFrame::BASELINE) {
12431245
BaselineFrame* frame = BaselineFrame::cast(it.frame());
1244-
if (!deopt_all && frame->function().shared() != shared_) continue;
12451246
int bytecode_offset = frame->GetBytecodeOffset();
12461247
Address* pc_addr = frame->pc_address();
12471248
Address advance = BUILTIN_CODE(isolate, InterpreterEnterAtNextBytecode)
12481249
->InstructionStart();
12491250
PointerAuthentication::ReplacePC(pc_addr, advance, kSystemPointerSize);
12501251
InterpretedFrame::cast(it.Reframe())
12511252
->PatchBytecodeOffset(bytecode_offset);
1253+
} else if (it.frame()->type() == StackFrame::INTERPRETED) {
1254+
// Check if the PC is a baseline entry trampoline. If it is, replace it
1255+
// with the corresponding interpreter entry trampoline.
1256+
// This is the case if a baseline function was inlined into a function
1257+
// we deoptimized in the debugger and are stepping into it.
1258+
JavaScriptFrame* frame = it.frame();
1259+
Address pc = frame->pc();
1260+
Builtins::Name builtin_index =
1261+
InstructionStream::TryLookupCode(isolate, pc);
1262+
if (builtin_index == Builtins::kBaselineEnterAtBytecode ||
1263+
builtin_index == Builtins::kBaselineEnterAtNextBytecode) {
1264+
Address* pc_addr = frame->pc_address();
1265+
Builtins::Name advance =
1266+
builtin_index == Builtins::kBaselineEnterAtBytecode
1267+
? Builtins::kInterpreterEnterAtBytecode
1268+
: Builtins::kInterpreterEnterAtNextBytecode;
1269+
Address advance_pc =
1270+
isolate->builtins()->builtin(advance).InstructionStart();
1271+
PointerAuthentication::ReplacePC(pc_addr, advance_pc,
1272+
kSystemPointerSize);
1273+
}
12521274
}
12531275
}
12541276
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright 2021 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Flags: --sparkplug --allow-natives-syntax
6+
7+
function f() {
8+
debugger;
9+
return 1;
10+
}
11+
12+
function g() {
13+
return f(); // Break
14+
}
15+
16+
function h() {
17+
return g();
18+
}
19+
20+
// Ensure FeedbackVector to consider f for inlining.
21+
%EnsureFeedbackVectorForFunction(f);
22+
%CompileBaseline(g);
23+
24+
%PrepareFunctionForOptimization(h);
25+
h();
26+
h();
27+
28+
var Debug = debug.Debug;
29+
var step_count = 0;
30+
var exception = null;
31+
32+
function listener(event, exec_state, event_data, data) {
33+
if (event != Debug.DebugEvent.Break) return;
34+
try {
35+
if (step_count == 0) {
36+
exec_state.prepareStep(Debug.StepAction.StepOut);
37+
} else {
38+
assertTrue(exec_state.frame().sourceLineText().includes('Break'));
39+
}
40+
step_count++;
41+
} catch (e) {
42+
exception = e;
43+
print(e);
44+
}
45+
}
46+
47+
Debug.setListener(listener);
48+
%OptimizeFunctionOnNextCall(h);
49+
h();
50+
Debug.setListener(null);
51+
assertNull(exception);
52+
assertEquals(2, step_count);

0 commit comments

Comments
 (0)