ART: Change lock dumping
Return dex registers as well as dex PCs from FindLocksAtDexPc.
It is necessary to return the registers as the register used for
a monitor-enter operation may be aliased and overwritten by the
time the requested dex PC is reached.
It is at this point necessary to return a set of registers as
optimizations may have eliminated dead registers, and the verifier
has no notion of liveness.
A client of FindLocksAtDexPc should not assume that all registers
can be successfully retrieved from a stack frame, with the possibility
of none. Only a properly verified method (i.e., lock verification succeeded)
implies that at least one register should work for all locks held at
any point in the program.
Bug: 68703210
Test: art/test/testrunner/testrunner.py -b --host -t 167
Change-Id: I9027787e395cf8df0e7699a606665edb2ecb5136
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index cdc55bd..d5520d9 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -1401,26 +1401,38 @@
// Ask the verifier for the dex pcs of all the monitor-enter instructions corresponding to
// the locks held in this stack frame.
- std::vector<uint32_t> monitor_enter_dex_pcs;
+ std::vector<verifier::MethodVerifier::DexLockInfo> monitor_enter_dex_pcs;
verifier::MethodVerifier::FindLocksAtDexPc(m, dex_pc, &monitor_enter_dex_pcs);
- for (uint32_t monitor_dex_pc : monitor_enter_dex_pcs) {
- // The verifier works in terms of the dex pcs of the monitor-enter instructions.
- // We want the registers used by those instructions (so we can read the values out of them).
- const Instruction* monitor_enter_instruction =
- Instruction::At(&code_item->insns_[monitor_dex_pc]);
+ for (verifier::MethodVerifier::DexLockInfo& dex_lock_info : monitor_enter_dex_pcs) {
+ // As a debug check, check that dex PC corresponds to a monitor-enter.
+ if (kIsDebugBuild) {
+ const Instruction* monitor_enter_instruction =
+ Instruction::At(&code_item->insns_[dex_lock_info.dex_pc]);
+ CHECK_EQ(monitor_enter_instruction->Opcode(), Instruction::MONITOR_ENTER)
+ << "expected monitor-enter @" << dex_lock_info.dex_pc << "; was "
+ << reinterpret_cast<const void*>(monitor_enter_instruction);
+ }
- // Quick sanity check.
- CHECK_EQ(monitor_enter_instruction->Opcode(), Instruction::MONITOR_ENTER)
- << "expected monitor-enter @" << monitor_dex_pc << "; was "
- << reinterpret_cast<const void*>(monitor_enter_instruction);
-
- uint16_t monitor_register = monitor_enter_instruction->VRegA();
- uint32_t value;
- bool success = stack_visitor->GetVReg(m, monitor_register, kReferenceVReg, &value);
- CHECK(success) << "Failed to read v" << monitor_register << " of kind "
- << kReferenceVReg << " in method " << m->PrettyMethod();
- mirror::Object* o = reinterpret_cast<mirror::Object*>(value);
- callback(o, callback_context);
+ // Iterate through the set of dex registers, as the compiler may not have held all of them
+ // live.
+ bool success = false;
+ for (uint32_t dex_reg : dex_lock_info.dex_registers) {
+ uint32_t value;
+ success = stack_visitor->GetVReg(m, dex_reg, kReferenceVReg, &value);
+ if (success) {
+ mirror::Object* o = reinterpret_cast<mirror::Object*>(value);
+ callback(o, callback_context);
+ break;
+ }
+ }
+ DCHECK(success) << "Failed to find/read reference for monitor-enter at dex pc "
+ << dex_lock_info.dex_pc
+ << " in method "
+ << m->PrettyMethod();
+ if (!success) {
+ LOG(WARNING) << "Had a lock reported for dex pc " << dex_lock_info.dex_pc
+ << " but was not able to fetch a corresponding object!";
+ }
}
}