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!";
+    }
   }
 }