[vm] Fix more cases of the profiler failing to identify the entry frame.

TEST=dart-fuzz
Bug: https://github.com/dart-lang/sdk/issues/63105
Change-Id: I081a719a1d91c0e003a45ce1249e7856aa46a530
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/495784
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Alexander Aprelev <aam@google.com>
This commit is contained in:
Ryan Macnak
2026-04-15 15:23:51 -07:00
committed by dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent 9c90b215c9
commit 3e05df3856
4 changed files with 39 additions and 8 deletions
@@ -5268,8 +5268,10 @@ void Assembler::LeaveDartFrame(intptr_t fp_sp_dist) {
subi(PP, PP, kHeapObjectTag);
}
set_constant_pool_allowed(false);
lx(FP, Address(SP, fp_offset));
// Update RA first so the profiler can identify the frame as the entry frame
// after FP is updated but before the return instruction.
lx(RA, Address(SP, ra_offset));
lx(FP, Address(SP, fp_offset));
addi(SP, SP, -fp_sp_dist);
}
+20 -6
View File
@@ -1349,18 +1349,27 @@ void Simulator::HandleRList(Instr* instr, bool load) {
set_register(rn, rn_val);
}
if (rlist == ((1 << FP) | (1 << PC))) {
// Special case `ldmia {fp, pc}` for LeaveDartFrame so that the profiler
// does not get confused by observing the update to fp before pc when our
// caller is the entry stub, i.e., failing to identify the entry frame. On
// real hardware, the profiler's signal handler cannot observe a partially
// executued load-multiple instruction.
// Special case `ldmia {fp, lr/pc}` for LeaveDartFrame[AndReturn] so that
// the profiler does not get confused by observing the update to fp before
// lr/pc when our caller is the entry stub, i.e., failing to identify the
// entry frame. On real hardware, the profiler's signal handler cannot
// observe a partially executued load-multiple instruction.
if (load && rlist == ((1 << FP) | (1 << PC))) {
COMPILE_ASSERT(FP < PC);
int32_t new_fp = ReadW(address, instr);
address += 4;
int32_t new_pc = ReadW(address, instr);
address += 4;
set_register(PC, new_pc);
set_register(FP, new_fp);
} else if (load && rlist == ((1 << FP) | (1 << LR))) {
COMPILE_ASSERT(FP < LR);
int32_t new_fp = ReadW(address, instr);
address += 4;
int32_t new_lr = ReadW(address, instr);
address += 4;
set_register(LR, new_lr);
set_register(FP, new_fp);
} else {
int reg = 0;
while (rlist != 0) {
@@ -1592,6 +1601,11 @@ DART_FORCE_INLINE void Simulator::DecodeType01(Instr* instr) {
Register rm = instr->RmField();
int32_t rm_val = get_register(rm);
intptr_t pc = get_pc();
// Set LR first so that the profiler does not get confused by
// observing the update to PC without the update to LR when we are
// calling out of the entry stub, i.e., failing to indentify the entry
// stub. On real hardware, the profiler's signal handler cannot
// observe a partially execute BLR.
set_register(LR, pc + Instr::kInstrSize);
set_pc(rm_val);
break;
+6 -1
View File
@@ -2052,8 +2052,13 @@ void Simulator::DecodeUnconditionalBranchReg(Instr* instr) {
const Register rn = instr->RnField();
const int64_t dest = get_register(rn, instr->RnMode());
const int64_t ret = get_pc() + Instr::kInstrSize;
set_pc(dest);
// Set LR first so that the profiler does not get confused by
// observing the update to PC without the update to LR when we are
// calling out of the entry stub, i.e., failing to indentify the entry
// stub. On real hardware, the profiler's signal handler cannot
// observe a partially execute BLR.
set_register(instr, LR, ret);
set_pc(dest);
break;
}
case 2: {
+10
View File
@@ -1047,6 +1047,11 @@ void Simulator::Interpret(CInstr instr) {
} else if (instr.rs2() == ZR) {
// JALR
uintx_t target = get_xreg(instr.rs1());
// Set RA first so that the profiler does not get confused by
// observing the update to PC without the update to RA when we are
// calling out of the entry stub, i.e., failing to indentify the entry
// stub. On real hardware, the profiler's signal handler cannot
// observe a partially execute JALR.
set_xreg(RA, pc_ + instr.length());
pc_ = target;
CheckLandingPad(instr.rs1());
@@ -1295,6 +1300,11 @@ DART_FORCE_INLINE
void Simulator::InterpretJALR(Instr instr) {
uintx_t base = get_xreg(instr.rs1());
uintx_t offset = static_cast<uintx_t>(instr.itype_imm());
// Set RA first so that the profiler does not get confused by
// observing the update to PC without the update to RA when we are
// calling out of the entry stub, i.e., failing to indentify the entry
// stub. On real hardware, the profiler's signal handler cannot
// observe a partially execute JALR.
set_xreg(instr.rd(), pc_ + instr.length());
pc_ = base + offset;
CheckLandingPad(instr.rs1());