[vm] More thoroughly clobber volatile registers in the ARM simulators.

TEST=ci
Change-Id: I04336abf00eed29e5301625ab91e63887cdaefbd
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/250762
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Ryan Macnak 2022-07-07 16:02:51 +00:00 committed by Commit Bot
parent 709c4202b5
commit 6bfe5c4d9b
7 changed files with 61 additions and 59 deletions

View file

@ -606,6 +606,7 @@ const RegList kAllFpuRegistersList = (1 << kNumberOfFpuRegisters) - 1;
// C++ ABI call registers.
const RegList kAbiArgumentCpuRegs =
(1 << R0) | (1 << R1) | (1 << R2) | (1 << R3);
const RegList kAbiVolatileCpuRegs = kAbiArgumentCpuRegs | (1 << IP) | (1 << LR);
#if defined(DART_TARGET_OS_MACOS) || defined(DART_TARGET_OS_MACOS_IOS)
const RegList kAbiPreservedCpuRegs =
(1 << R4) | (1 << R5) | (1 << R6) | (1 << R8) | (1 << R10) | (1 << R11);

View file

@ -451,9 +451,9 @@ const RegList kAllFpuRegistersList = 0xFFFFFFFF;
// C++ ABI call registers.
const RegList kAbiArgumentCpuRegs =
R(R0) | R(R1) | R(R2) | R(R3) | R(R4) | R(R5) | R(R6) | R(R7);
const RegList kAbiVolatileCpuRegs =
kAbiArgumentCpuRegs | R(R8) | R(R9) | R(R10) | R(R11) | R(R12) | R(R13) |
R(R14) | R(R15) | R(R16) | R(R17);
const RegList kAbiVolatileCpuRegs = kAbiArgumentCpuRegs | R(R8) | R(R9) |
R(R10) | R(R11) | R(R12) | R(R13) | R(R14) |
R(R15) | R(R16) | R(R17) | R(LR);
#if defined(DART_TARGET_OS_FUCHSIA)
// We rely on R18 not being touched by Dart generated assembly or stubs at all.
// We rely on that any calls into C++ also preserve R18.

View file

@ -449,8 +449,9 @@ const RegList kAllFpuRegistersList = 0xFFFFFFFF;
constexpr RegList kAbiArgumentCpuRegs =
R(A0) | R(A1) | R(A2) | R(A3) | R(A4) | R(A5) | R(A6) | R(A7);
constexpr RegList kAbiVolatileCpuRegs =
kAbiArgumentCpuRegs | R(T0) | R(T1) | R(T2) | R(T3) | R(T4) | R(T5) | R(T6);
constexpr RegList kAbiVolatileCpuRegs = kAbiArgumentCpuRegs | R(T0) | R(T1) |
R(T2) | R(T3) | R(T4) | R(T5) | R(T6) |
R(RA);
constexpr RegList kAbiPreservedCpuRegs = R(S1) | R(S2) | R(S3) | R(S4) | R(S5) |
R(S6) | R(S7) | R(S8) | R(S9) |
R(S10) | R(S11);

View file

@ -1428,8 +1428,7 @@ void Simulator::SupervisorCall(Instr* instr) {
SimulatorRuntimeCall target =
reinterpret_cast<SimulatorRuntimeCall>(external);
target(arguments);
set_register(R0, icount_); // Zap result register from void function.
set_register(R1, icount_);
ClobberVolatileRegisters();
} else if (redirection->call_kind() == kLeafRuntimeCall) {
ASSERT((0 <= redirection->argument_count()) &&
(redirection->argument_count() <= 5));
@ -1441,8 +1440,8 @@ void Simulator::SupervisorCall(Instr* instr) {
SimulatorLeafRuntimeCall target =
reinterpret_cast<SimulatorLeafRuntimeCall>(external);
r0 = InvokeLeafRuntime(target, r0, r1, r2, r3, r4);
ClobberVolatileRegisters();
set_register(R0, r0); // Set returned result from function.
set_register(R1, icount_); // Zap unused result register.
} else if (redirection->call_kind() == kLeafFloatRuntimeCall) {
ASSERT((0 <= redirection->argument_count()) &&
(redirection->argument_count() <= 2));
@ -1454,6 +1453,7 @@ void Simulator::SupervisorCall(Instr* instr) {
double d0 = get_dregister(D0);
double d1 = get_dregister(D1);
d0 = InvokeFloatLeafRuntime(target, d0, d1);
ClobberVolatileRegisters();
set_dregister(D0, d0);
} else {
// If we're not doing "hardfp", we must be doing "soft" or "softfp",
@ -1467,6 +1467,7 @@ void Simulator::SupervisorCall(Instr* instr) {
double d0 = bit_cast<double, int64_t>(a0);
double d1 = bit_cast<double, int64_t>(a1);
d0 = InvokeFloatLeafRuntime(target, d0, d1);
ClobberVolatileRegisters();
a0 = bit_cast<int64_t, double>(d0);
r0 = Utils::Low32Bits(a0);
r1 = Utils::High32Bits(a0);
@ -1482,29 +1483,9 @@ void Simulator::SupervisorCall(Instr* instr) {
Dart_NativeFunction target_func =
reinterpret_cast<Dart_NativeFunction>(get_register(R1));
wrapper(arguments, target_func);
set_register(R0, icount_); // Zap result register from void function.
set_register(R1, icount_);
ClobberVolatileRegisters();
}
// Zap caller-saved registers, since the actual runtime call could have
// used them.
set_register(R2, icount_);
set_register(R3, icount_);
set_register(IP, icount_);
set_register(LR, icount_);
double zap_dvalue = static_cast<double>(icount_);
// Do not zap D0, as it may contain a float result.
for (int i = D1; i <= D7; i++) {
set_dregister(static_cast<DRegister>(i), zap_dvalue);
}
// The above loop also zaps overlapping registers S2-S15.
// Registers D8-D15 (overlapping with S16-S31) are preserved.
#if defined(VFPv3_D32)
for (int i = D16; i <= D31; i++) {
set_dregister(static_cast<DRegister>(i), zap_dvalue);
}
#endif
// Return.
set_pc(saved_lr);
} else {
@ -1525,6 +1506,29 @@ void Simulator::SupervisorCall(Instr* instr) {
}
}
void Simulator::ClobberVolatileRegisters() {
// Clear atomic reservation.
exclusive_access_addr_ = exclusive_access_value_ = 0;
for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) {
if ((kAbiVolatileCpuRegs & (1 << i)) != 0) {
registers_[i] = icount_;
}
}
double zap_dvalue = static_cast<double>(icount_);
for (int i = D0; i <= D7; i++) {
set_dregister(static_cast<DRegister>(i), zap_dvalue);
}
// The above loop also zaps overlapping registers S2-S15.
// Registers D8-D15 (overlapping with S16-S31) are preserved.
#if defined(VFPv3_D32)
for (int i = D16; i <= D31; i++) {
set_dregister(static_cast<DRegister>(i), zap_dvalue);
}
#endif
}
// Handle execution based on instruction types.
// Instruction types 0 and 1 are both rolled into one function because they

View file

@ -233,6 +233,8 @@ class Simulator {
// Executes ARM instructions until the PC reaches kEndSimulatingPC.
void Execute();
void ClobberVolatileRegisters();
// Returns true if tracing of executed instructions is enabled.
bool IsTracingExecution() const;

View file

@ -1711,9 +1711,7 @@ void Simulator::DoRedirectedCall(Instr* instr) {
SimulatorRuntimeCall target =
reinterpret_cast<SimulatorRuntimeCall>(external);
target(*arguments);
// Zap result register from void function.
set_register(instr, R0, icount_);
set_register(instr, R1, icount_);
ClobberVolatileRegisters();
} else if (redirection->call_kind() == kLeafRuntimeCall) {
ASSERT((0 <= redirection->argument_count()) &&
(redirection->argument_count() <= 8));
@ -1729,8 +1727,8 @@ void Simulator::DoRedirectedCall(Instr* instr) {
const int64_t r7 = get_register(R7);
const int64_t res =
InvokeLeafRuntime(target, r0, r1, r2, r3, r4, r5, r6, r7);
ClobberVolatileRegisters();
set_register(instr, R0, res); // Set returned result from function.
set_register(instr, R1, icount_); // Zap unused result register.
} else if (redirection->call_kind() == kLeafFloatRuntimeCall) {
ASSERT((0 <= redirection->argument_count()) &&
(redirection->argument_count() <= 8));
@ -1746,6 +1744,7 @@ void Simulator::DoRedirectedCall(Instr* instr) {
const double d7 = bit_cast<double, int64_t>(get_vregisterd(V7, 0));
const double res =
InvokeFloatLeafRuntime(target, d0, d1, d2, d3, d4, d5, d6, d7);
ClobberVolatileRegisters();
set_vregisterd(V0, 0, bit_cast<int64_t, double>(res));
set_vregisterd(V0, 1, 0);
} else {
@ -1757,34 +1756,9 @@ void Simulator::DoRedirectedCall(Instr* instr) {
Dart_NativeFunction target =
reinterpret_cast<Dart_NativeFunction>(get_register(R1));
wrapper(arguments, target);
// Zap result register from void function.
set_register(instr, R0, icount_);
set_register(instr, R1, icount_);
ClobberVolatileRegisters();
}
// Zap caller-saved registers, since the actual runtime call could have
// used them.
set_register(NULL, R2, icount_);
set_register(NULL, R3, icount_);
set_register(NULL, R4, icount_);
set_register(NULL, R5, icount_);
set_register(NULL, R6, icount_);
set_register(NULL, R7, icount_);
set_register(NULL, R8, icount_);
set_register(NULL, R9, icount_);
set_register(NULL, R10, icount_);
set_register(NULL, R11, icount_);
set_register(NULL, R12, icount_);
set_register(NULL, R13, icount_);
set_register(NULL, R14, icount_);
set_register(NULL, R15, icount_);
set_register(NULL, IP0, icount_);
set_register(NULL, IP1, icount_);
set_register(NULL, R18, icount_);
set_register(NULL, LR, icount_);
// TODO(zra): Zap caller-saved fpu registers.
// Return.
set_pc(saved_lr);
} else {
@ -1792,6 +1766,24 @@ void Simulator::DoRedirectedCall(Instr* instr) {
}
}
void Simulator::ClobberVolatileRegisters() {
// Clear atomic reservation.
exclusive_access_addr_ = exclusive_access_value_ = 0;
for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) {
if ((kAbiVolatileCpuRegs & (1 << i)) != 0) {
registers_[i] = icount_;
}
}
for (intptr_t i = 0; i < kNumberOfFpuRegisters; i++) {
if ((kAbiVolatileFpuRegs & (1 << i)) != 0) {
vregisters_[i].bits.i64[0] = icount_;
vregisters_[i].bits.i64[1] = icount_;
}
}
}
void Simulator::DecodeExceptionGen(Instr* instr) {
if ((instr->Bits(0, 2) == 1) && (instr->Bits(2, 3) == 0) &&
(instr->Bits(21, 3) == 0)) {

View file

@ -240,6 +240,8 @@ class Simulator {
// Executes ARM64 instructions until the PC reaches kEndSimulatingPC.
void Execute();
void ClobberVolatileRegisters();
// Returns true if tracing of executed instructions is enabled.
bool IsTracingExecution() const;