Fix a few more JDWP bugs.

My previous division by 2 of dex PCs was wrong-headed. I need to fix the test
instead to not try to set a breakpoint in the middle of an instruction.

Also, we weren't reporting some class-specific events that we should have done
because of an InstanceOf/IsAssignableFrom mixup.

Change-Id: I187fc0977955038270866c9d7d28b0a709408aa0
diff --git a/src/debugger.cc b/src/debugger.cc
index 494ee73..d2c05b7 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -122,12 +122,12 @@
 
 struct Breakpoint {
   Method* method;
-  uint32_t pc;
-  Breakpoint(Method* method, uint32_t pc) : method(method), pc(pc) {}
+  uint32_t dex_pc;
+  Breakpoint(Method* method, uint32_t dex_pc) : method(method), dex_pc(dex_pc) {}
 };
 
 static std::ostream& operator<<(std::ostream& os, const Breakpoint& rhs) {
-  os << "Breakpoint[" << PrettyMethod(rhs.method) << " @" << rhs.pc << "]";
+  os << "Breakpoint[" << PrettyMethod(rhs.method) << " @" << rhs.dex_pc << "]";
   return os;
 }
 
@@ -184,9 +184,8 @@
 
 static bool IsBreakpoint(Method* m, uint32_t dex_pc) {
   MutexLock mu(gBreakpointsLock);
-  uint32_t pc = dex_pc / 2; // dex bytecodes are twice the size JDWP expects.
   for (size_t i = 0; i < gBreakpoints.size(); ++i) {
-    if (gBreakpoints[i].method == m && gBreakpoints[i].pc == pc) {
+    if (gBreakpoints[i].method == m && gBreakpoints[i].dex_pc == dex_pc) {
       VLOG(jdwp) << "Hit breakpoint #" << i << ": " << gBreakpoints[i];
       return true;
     }
@@ -893,12 +892,10 @@
 bool Dbg::MatchType(JDWP::RefTypeId instClassId, JDWP::RefTypeId classId) {
   JDWP::JdwpError status;
   Class* c1 = DecodeClass(instClassId, status);
+  CHECK(c1 != NULL);
   Class* c2 = DecodeClass(classId, status);
-  if (c1 == NULL || c2 == NULL) {
-    // TODO: it doesn't seem like we can do any better here?
-    return false;
-  }
-  return c1->InstanceOf(c2);
+  CHECK(c2 != NULL);
+  return c1->IsAssignableFrom(c2);
 }
 
 static JDWP::FieldId ToFieldId(const Field* f) {
@@ -941,7 +938,7 @@
     location.typeTag = c->IsInterface() ? JDWP::TT_INTERFACE : JDWP::TT_CLASS;
     location.classId = gRegistry->Add(c);
     location.methodId = ToMethodId(m);
-    location.idx = m->IsNative() ? -1 : m->ToDexPC(native_pc) / 2;
+    location.idx = m->IsNative() ? -1 : m->ToDexPC(native_pc);
   }
 }
 
@@ -1455,6 +1452,10 @@
         : found(false), depth(0), desired_frame_number(desired_frame_number), pFrameId(pFrameId), pLoc(pLoc) {
     }
     virtual void VisitFrame(const Frame& f, uintptr_t pc) {
+      if (found) {
+        return;
+      }
+
       // TODO: we'll need to skip callee-save frames too.
       if (!f.HasMethod()) {
         return; // The debugger can't do anything useful with a frame that has no Method*.
@@ -1681,7 +1682,7 @@
   location.typeTag = c->IsInterface() ? JDWP::TT_INTERFACE : JDWP::TT_CLASS;
   location.classId = gRegistry->Add(c);
   location.methodId = ToMethodId(m);
-  location.idx = m->IsNative() ? -1 : dex_pc / 2;
+  location.idx = m->IsNative() ? -1 : dex_pc;
 
   // Note we use "NoReg" so we don't keep track of references that are
   // never actually sent to the debugger. 'this_id' is only used to
@@ -1855,7 +1856,7 @@
   MutexLock mu(gBreakpointsLock);
   Method* m = FromMethodId(location->methodId);
   for (size_t i = 0; i < gBreakpoints.size(); ++i) {
-    if (gBreakpoints[i].method == m && gBreakpoints[i].pc == location->idx) {
+    if (gBreakpoints[i].method == m && gBreakpoints[i].dex_pc == location->idx) {
       VLOG(jdwp) << "Removed breakpoint #" << i << ": " << gBreakpoints[i];
       gBreakpoints.erase(gBreakpoints.begin() + i);
       return;