Fix vmap handling. Adjust all PCs by -2 in WalkStack.
Vmap handling didn't increment the register when it got the first hit in
the core spill mask (bug exposed by register promotion). Adjust PCs by -2
in WalkStack so that ToDexPc calls don't need adjustment. This corrects
line number information on "run-test 054".
Change-Id: Iebfb4109b5234bb7357b5ba538883c28dfc7cb26
diff --git a/src/exception_test.cc b/src/exception_test.cc
index 7acc584..fd012cd 100644
--- a/src/exception_test.cc
+++ b/src/exception_test.cc
@@ -98,11 +98,15 @@
ASSERT_EQ(kStackAlignment, 16);
ASSERT_EQ(sizeof(uintptr_t), sizeof(uint32_t));
+ // Create two fake stack frames with mapping data created in SetUp. We map offset 3 in the code
+ // two dex pc 3, however, we set the return pc to 5 as the stack walker always subtracts two
+ // from a return pc.
+
// Create/push fake 16byte stack frame for method g
fake_stack[top_of_stack++] = reinterpret_cast<uintptr_t>(method_g_);
fake_stack[top_of_stack++] = 0;
fake_stack[top_of_stack++] = 0;
- fake_stack[top_of_stack++] = reinterpret_cast<uintptr_t>(method_f_->GetCode()) + 3; // return pc
+ fake_stack[top_of_stack++] = reinterpret_cast<uintptr_t>(method_f_->GetCode()) + 5; // return pc
// Create/push fake 16byte stack frame for method f
fake_stack[top_of_stack++] = reinterpret_cast<uintptr_t>(method_f_);
diff --git a/src/thread.cc b/src/thread.cc
index e4281a0..a481aa6 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -957,6 +957,7 @@
jobject local_ref_;
};
+
void Thread::WalkStack(StackVisitor* visitor) const {
Frame frame = GetTopOfStack();
uintptr_t pc = top_of_managed_stack_pc_;
@@ -969,6 +970,11 @@
DCHECK(frame.GetMethod()->IsWithinCode(pc));
visitor->VisitFrame(frame, pc);
pc = frame.GetReturnPC();
+ // Move the PC back 2 bytes as a call will frequently terminate the
+ // decoding of a particular instruction and we want to make sure we
+ // get the Dex PC of the instruction with the call and not the
+ // instruction following.
+ pc -= 2;
}
if (record == NULL) {
break;
@@ -989,6 +995,11 @@
DCHECK(frame.GetMethod()->IsWithinCode(pc));
visitor->VisitFrame(frame, pc);
pc = frame.GetReturnPC();
+ // Move the PC back 2 bytes as a call will frequently terminate the
+ // decoding of a particular instruction and we want to make sure we
+ // get the Dex PC of the instruction with the call and not the
+ // instruction following.
+ pc -= 2;
}
if (include_upcall) {
visitor->VisitFrame(frame, pc);
@@ -1119,7 +1130,7 @@
if (method == NULL) {
// This is the upcall, we remember the frame and last_pc so that we may
// long jump to them
- handler_pc_ = pc;
+ handler_pc_ = pc + 2; // We want to return after the call instruction, wind forward 2 again
handler_frame_ = fr;
return;
}
@@ -1129,11 +1140,6 @@
} else if (method->IsNative()) {
native_method_count_++;
} else {
- // Move the PC back 2 bytes as a call will frequently terminate the
- // decoding of a particular instruction and we want to make sure we
- // get the Dex PC of the instruction with the call and not the
- // instruction following.
- pc -= 2;
dex_pc = method->ToDexPC(pc);
}
if (dex_pc != DexFile::kDexNoIndex) {
@@ -1206,9 +1212,6 @@
return gThread_daemon->GetBoolean(peer_);
}
-// blx is 2-byte in Thumb2. Need to offset PC back to a call site.
-static const int kThumb2InstSize = 2;
-
class ReferenceMapVisitor : public Thread::StackVisitor {
public:
ReferenceMapVisitor(Context* context, Heap::RootVisitor* root_visitor, void* arg) :
@@ -1217,18 +1220,12 @@
void VisitFrame(const Frame& frame, uintptr_t pc) {
Method* m = frame.GetMethod();
-
// Process register map (which native and callee save methods don't have)
if (!m->IsNative() && !m->IsPhony()) {
UniquePtr<art::DexVerifier::RegisterMap> map(art::DexVerifier::GetExpandedRegisterMap(m));
-
- const uint8_t* reg_bitmap = art::DexVerifier::RegisterMapGetLine(
- map.get(),
- m->ToDexPC(pc -kThumb2InstSize));
-
+ const uint8_t* reg_bitmap = art::DexVerifier::RegisterMapGetLine(map.get(), m->ToDexPC(pc));
LOG(INFO) << "Visiting stack roots in " << PrettyMethod(m, false)
- << "@ PC: " << m->ToDexPC(pc - kThumb2InstSize);
-
+ << "@ PC: " << m->ToDexPC(pc);
CHECK(reg_bitmap != NULL);
ShortArray* vmap = m->GetVMapTable();
// For all dex registers
@@ -1237,7 +1234,7 @@
if (TestBitmap(reg, reg_bitmap)) {
// Is the reference in the context or on the stack?
bool in_context = false;
- int vmap_offset = -1;
+ uint32_t vmap_offset = 0xEBAD0FF5;
// TODO: take advantage of the registers being ordered
for (int i = 0; i < vmap->GetLength(); i++) {
if (vmap->Get(i) == reg) {
@@ -1250,15 +1247,16 @@
if (in_context) {
// Compute the register we need to load from the context
uint32_t spill_mask = m->GetCoreSpillMask();
- uint32_t reg = 0;
- for (int i = 0; i < vmap_offset; i++) {
- while ((spill_mask & 1) == 0) {
- CHECK_NE(spill_mask, 0u);
- spill_mask >>= 1;
- reg++;
- }
+ uint32_t matches = 0;
+ uint32_t spill_shifts = 0;
+ while (matches != (vmap_offset + 1)) {
+ CHECK_NE(spill_mask, 0u);
+ matches += spill_mask & 1; // Add 1 if the low bit is set
+ spill_mask >>= 1;
+ spill_shifts++;
}
- ref = reinterpret_cast<Object*>(context_->GetGPR(reg));
+ spill_shifts--; // wind back one as we want the last match
+ ref = reinterpret_cast<Object*>(context_->GetGPR(spill_shifts));
} else {
ref = reinterpret_cast<Object*>(frame.GetVReg(m ,reg));
}