Fix breakpoints.

My manual testing in jdb worked because I only ever set breakpoints at
offset 0, which is the same whether you're using bytecode or 16bitcode.

Change-Id: I7aae1961d08fc008af275ff0d1ae1f1e4619fa18
diff --git a/src/debugger.cc b/src/debugger.cc
index 12d4034..8c28cd9 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -177,8 +177,9 @@
 
 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 == dex_pc) {
+    if (gBreakpoints[i].method == m && gBreakpoints[i].pc == pc) {
       VLOG(jdwp) << "Hit breakpoint #" << i << ": " << gBreakpoints[i];
       return true;
     }
@@ -898,7 +899,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);
+    location.idx = m->IsNative() ? -1 : m->ToDexPC(native_pc) / 2;
   }
 }
 
@@ -1610,7 +1611,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;
+  location.idx = m->IsNative() ? -1 : dex_pc / 2;
 
   // 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
@@ -1667,30 +1668,24 @@
 }
 
 void Dbg::UpdateDebugger(int32_t dex_pc, Thread* self, Method** sp) {
-  if (!gDebuggerActive) {
+  if (!gDebuggerActive || dex_pc == -2 /* fake method exit */) {
     return;
   }
 
   Frame f(sp);
   f.Next(); // Skip callee save frame.
   Method* m = f.GetMethod();
-  int event_flags = 0;
 
-  // Update xtra.currentPc on every instruction.  We need to do this if
-  // there's a chance that we could get suspended.  This can happen if
-  // event_flags != 0 here, or somebody manually requests a suspend
-  // (which gets handled at PERIOD_CHECKS time).  One place where this
-  // needs to be correct is in dvmAddSingleStep().
-  //dvmExportPC(pc, fp);
-
-  // We use a pc of -1 to represent method entry, since we might branch back to pc 0 later.
   if (dex_pc == -1) {
-    event_flags |= kMethodEntry;
+    // We use a pc of -1 to represent method entry, since we might branch back to pc 0 later.
+    // This means that for this special notification, there can't be anything else interesting
+    // going on, so we're done already.
+    Dbg::PostLocationEvent(m, 0, GetThis(f), kMethodEntry);
+    return;
   }
 
-  // See if we have a breakpoint here.
-  // Depending on the "mods" associated with event(s) on this address,
-  // we may or may not actually send a message to the debugger.
+  int event_flags = 0;
+
   if (IsBreakpoint(m, dex_pc)) {
     event_flags |= kBreakpoint;
   }
diff --git a/src/jdwp/jdwp.h b/src/jdwp/jdwp.h
index 7bbc54f..a3f4b69 100644
--- a/src/jdwp/jdwp.h
+++ b/src/jdwp/jdwp.h
@@ -79,6 +79,8 @@
   uint64_t idx; // A Dex PC.
 };
 std::ostream& operator<<(std::ostream& os, const JdwpLocation& rhs);
+bool operator==(const JdwpLocation& lhs, const JdwpLocation& rhs);
+bool operator!=(const JdwpLocation& lhs, const JdwpLocation& rhs);
 
 /*
  * How we talk to the debugger.
diff --git a/src/jdwp/jdwp_event.cc b/src/jdwp/jdwp_event.cc
index 5101f2f..285caf3 100644
--- a/src/jdwp/jdwp_event.cc
+++ b/src/jdwp/jdwp_event.cc
@@ -326,10 +326,10 @@
  * Run through the list and remove any entries with an expired "count" mod
  * from the event list, then free the match list.
  */
-void JdwpState::CleanupMatchList(JdwpEvent** matchList, int matchCount) {
+void JdwpState::CleanupMatchList(JdwpEvent** matchList, int match_count) {
   JdwpEvent** ppEvent = matchList;
 
-  while (matchCount--) {
+  while (match_count--) {
     JdwpEvent* pEvent = *ppEvent;
 
     for (int i = 0; i < pEvent->modCount; i++) {
@@ -369,21 +369,6 @@
 }
 
 /*
- * See if two locations are equal.
- *
- * It's tempting to do a bitwise compare ("struct ==" or memcmp), but if
- * the storage wasn't zeroed out there could be undefined values in the
- * padding.  Besides, the odds of "idx" being equal while the others aren't
- * is very small, so this is usually just a simple integer comparison.
- */
-static inline bool LocationMatch(const JdwpLocation* pLoc1, const JdwpLocation* pLoc2) {
-  return pLoc1->idx == pLoc2->idx &&
-      pLoc1->methodId == pLoc2->methodId &&
-      pLoc1->classId == pLoc2->classId &&
-      pLoc1->typeTag == pLoc2->typeTag;
-}
-
-/*
  * See if the event's mods match up with the contents of "basket".
  *
  * If we find a Count mod before rejecting an event, we decrement it.  We
@@ -422,7 +407,7 @@
       }
       break;
     case MK_LOCATION_ONLY:
-      if (!LocationMatch(&pMod->locationOnly.loc, basket->pLoc)) {
+      if (pMod->locationOnly.loc != *basket->pLoc) {
         return false;
       }
       break;
@@ -486,10 +471,10 @@
  * Scan through the list of matches and determine the most severe
  * suspension policy.
  */
-static JdwpSuspendPolicy scanSuspendPolicy(JdwpEvent** matchList, int matchCount) {
+static JdwpSuspendPolicy scanSuspendPolicy(JdwpEvent** matchList, int match_count) {
   JdwpSuspendPolicy policy = SP_NONE;
 
-  while (matchCount--) {
+  while (match_count--) {
     if ((*matchList)->suspendPolicy > policy) {
       policy = (*matchList)->suspendPolicy;
     }
@@ -757,40 +742,40 @@
   }
 
   JdwpEvent** matchList = AllocMatchList(numEvents);
-  int matchCount = 0;
+  int match_count = 0;
   ExpandBuf* pReq = NULL;
   JdwpSuspendPolicy suspendPolicy = SP_NONE;
 
   {
     MutexLock mu(event_lock_);
     if ((eventFlags & Dbg::kBreakpoint) != 0) {
-      FindMatchingEvents(EK_BREAKPOINT, &basket, matchList, &matchCount);
+      FindMatchingEvents(EK_BREAKPOINT, &basket, matchList, &match_count);
     }
     if ((eventFlags & Dbg::kSingleStep) != 0) {
-      FindMatchingEvents(EK_SINGLE_STEP, &basket, matchList, &matchCount);
+      FindMatchingEvents(EK_SINGLE_STEP, &basket, matchList, &match_count);
     }
     if ((eventFlags & Dbg::kMethodEntry) != 0) {
-      FindMatchingEvents(EK_METHOD_ENTRY, &basket, matchList, &matchCount);
+      FindMatchingEvents(EK_METHOD_ENTRY, &basket, matchList, &match_count);
     }
     if ((eventFlags & Dbg::kMethodExit) != 0) {
-      FindMatchingEvents(EK_METHOD_EXIT, &basket, matchList, &matchCount);
+      FindMatchingEvents(EK_METHOD_EXIT, &basket, matchList, &match_count);
 
       // TODO: match EK_METHOD_EXIT_WITH_RETURN_VALUE too; we need to include the 'value', though.
-      //FindMatchingEvents(EK_METHOD_EXIT_WITH_RETURN_VALUE, &basket, matchList, &matchCount);
+      //FindMatchingEvents(EK_METHOD_EXIT_WITH_RETURN_VALUE, &basket, matchList, &match_count);
     }
-    if (matchCount != 0) {
-      VLOG(jdwp) << "EVENT: " << matchList[0]->eventKind << "(" << matchCount << " total) "
+    if (match_count != 0) {
+      VLOG(jdwp) << "EVENT: " << matchList[0]->eventKind << "(" << match_count << " total) "
                  << basket.className << "." << Dbg::GetMethodName(pLoc->classId, pLoc->methodId)
                  << " thread=" << (void*) basket.threadId << " code=" << (void*) pLoc->idx << ")";
 
-      suspendPolicy = scanSuspendPolicy(matchList, matchCount);
+      suspendPolicy = scanSuspendPolicy(matchList, match_count);
       VLOG(jdwp) << "  suspendPolicy=" << suspendPolicy;
 
       pReq = eventPrep();
       expandBufAdd1(pReq, suspendPolicy);
-      expandBufAdd4BE(pReq, matchCount);
+      expandBufAdd4BE(pReq, match_count);
 
-      for (int i = 0; i < matchCount; i++) {
+      for (int i = 0; i < match_count; i++) {
         expandBufAdd1(pReq, matchList[i]->eventKind);
         expandBufAdd4BE(pReq, matchList[i]->requestId);
         expandBufAdd8BE(pReq, basket.threadId);
@@ -798,7 +783,7 @@
       }
     }
 
-    CleanupMatchList(matchList, matchCount);
+    CleanupMatchList(matchList, match_count);
   }
 
   /* send request and possibly suspend ourselves */
@@ -814,7 +799,7 @@
     Dbg::ThreadContinuing(old_state);
   }
 
-  return matchCount != 0;
+  return match_count != 0;
 }
 
 /*
@@ -840,37 +825,37 @@
 
   ExpandBuf* pReq = NULL;
   JdwpSuspendPolicy suspendPolicy = SP_NONE;
-  int matchCount = 0;
+  int match_count = 0;
   {
     // Don't allow the list to be updated while we scan it.
     MutexLock mu(event_lock_);
     JdwpEvent** matchList = AllocMatchList(numEvents);
 
     if (start) {
-      FindMatchingEvents(EK_THREAD_START, &basket, matchList, &matchCount);
+      FindMatchingEvents(EK_THREAD_START, &basket, matchList, &match_count);
     } else {
-      FindMatchingEvents(EK_THREAD_DEATH, &basket, matchList, &matchCount);
+      FindMatchingEvents(EK_THREAD_DEATH, &basket, matchList, &match_count);
     }
 
-    if (matchCount != 0) {
-      VLOG(jdwp) << "EVENT: " << matchList[0]->eventKind << "(" << matchCount << " total) "
+    if (match_count != 0) {
+      VLOG(jdwp) << "EVENT: " << matchList[0]->eventKind << "(" << match_count << " total) "
                    << "thread=" << (void*) basket.threadId << ")";
 
-      suspendPolicy = scanSuspendPolicy(matchList, matchCount);
+      suspendPolicy = scanSuspendPolicy(matchList, match_count);
       VLOG(jdwp) << "  suspendPolicy=" << suspendPolicy;
 
       pReq = eventPrep();
       expandBufAdd1(pReq, suspendPolicy);
-      expandBufAdd4BE(pReq, matchCount);
+      expandBufAdd4BE(pReq, match_count);
 
-      for (int i = 0; i < matchCount; i++) {
+      for (int i = 0; i < match_count; i++) {
         expandBufAdd1(pReq, matchList[i]->eventKind);
         expandBufAdd4BE(pReq, matchList[i]->requestId);
         expandBufAdd8BE(pReq, basket.threadId);
       }
     }
 
-    CleanupMatchList(matchList, matchCount);
+    CleanupMatchList(matchList, match_count);
   }
 
   /* send request and possibly suspend ourselves */
@@ -885,7 +870,7 @@
     Dbg::ThreadContinuing(old_state);
   }
 
-  return matchCount != 0;
+  return match_count != 0;
 }
 
 /*
@@ -939,14 +924,14 @@
   }
 
   JdwpEvent** matchList = AllocMatchList(numEvents);
-  int matchCount = 0;
+  int match_count = 0;
   ExpandBuf* pReq = NULL;
   JdwpSuspendPolicy suspendPolicy = SP_NONE;
   {
     MutexLock mu(event_lock_);
-    FindMatchingEvents(EK_EXCEPTION, &basket, matchList, &matchCount);
-    if (matchCount != 0) {
-      VLOG(jdwp) << "EVENT: " << matchList[0]->eventKind << "(" << matchCount << " total)"
+    FindMatchingEvents(EK_EXCEPTION, &basket, matchList, &match_count);
+    if (match_count != 0) {
+      VLOG(jdwp) << "EVENT: " << matchList[0]->eventKind << "(" << match_count << " total)"
                    << " thread=" << (void*) basket.threadId
                    << " exceptId=" << (void*) exceptionId
                    << " caught=" << basket.caught << ")";
@@ -957,14 +942,14 @@
         VLOG(jdwp) << "  catch: " << *pCatchLoc;
       }
 
-      suspendPolicy = scanSuspendPolicy(matchList, matchCount);
+      suspendPolicy = scanSuspendPolicy(matchList, match_count);
       VLOG(jdwp) << "  suspendPolicy=" << suspendPolicy;
 
       pReq = eventPrep();
       expandBufAdd1(pReq, suspendPolicy);
-      expandBufAdd4BE(pReq, matchCount);
+      expandBufAdd4BE(pReq, match_count);
 
-      for (int i = 0; i < matchCount; i++) {
+      for (int i = 0; i < match_count; i++) {
         expandBufAdd1(pReq, matchList[i]->eventKind);
         expandBufAdd4BE(pReq, matchList[i]->requestId);
         expandBufAdd8BE(pReq, basket.threadId);
@@ -979,7 +964,7 @@
       Dbg::RegisterObjectId(exceptionId);
     }
 
-    CleanupMatchList(matchList, matchCount);
+    CleanupMatchList(matchList, match_count);
   }
 
   /* send request and possibly suspend ourselves */
@@ -995,7 +980,7 @@
     Dbg::ThreadContinuing(old_state);
   }
 
-  return matchCount != 0;
+  return match_count != 0;
 }
 
 /*
@@ -1019,17 +1004,17 @@
   }
 
   JdwpEvent** matchList = AllocMatchList(numEvents);
-  int matchCount = 0;
+  int match_count = 0;
   ExpandBuf* pReq = NULL;
   JdwpSuspendPolicy suspendPolicy = SP_NONE;
   {
     MutexLock mu(event_lock_);
-    FindMatchingEvents(EK_CLASS_PREPARE, &basket, matchList, &matchCount);
-    if (matchCount != 0) {
-      VLOG(jdwp) << "EVENT: " << matchList[0]->eventKind << "(" << matchCount << " total) "
+    FindMatchingEvents(EK_CLASS_PREPARE, &basket, matchList, &match_count);
+    if (match_count != 0) {
+      VLOG(jdwp) << "EVENT: " << matchList[0]->eventKind << "(" << match_count << " total) "
                    << "thread=" << (void*) basket.threadId << ") " << signature;
 
-      suspendPolicy = scanSuspendPolicy(matchList, matchCount);
+      suspendPolicy = scanSuspendPolicy(matchList, match_count);
       VLOG(jdwp) << "  suspendPolicy=" << suspendPolicy;
 
       if (basket.threadId == debugThreadId) {
@@ -1047,9 +1032,9 @@
 
       pReq = eventPrep();
       expandBufAdd1(pReq, suspendPolicy);
-      expandBufAdd4BE(pReq, matchCount);
+      expandBufAdd4BE(pReq, match_count);
 
-      for (int i = 0; i < matchCount; i++) {
+      for (int i = 0; i < match_count; i++) {
         expandBufAdd1(pReq, matchList[i]->eventKind);
         expandBufAdd4BE(pReq, matchList[i]->requestId);
         expandBufAdd8BE(pReq, basket.threadId);
@@ -1060,7 +1045,7 @@
         expandBufAdd4BE(pReq, status);
       }
     }
-    CleanupMatchList(matchList, matchCount);
+    CleanupMatchList(matchList, match_count);
   }
 
   /* send request and possibly suspend ourselves */
@@ -1075,7 +1060,7 @@
     Dbg::ThreadContinuing(old_state);
   }
 
-  return matchCount != 0;
+  return match_count != 0;
 }
 
 /*
diff --git a/src/jdwp/jdwp_main.cc b/src/jdwp/jdwp_main.cc
index a7e82aa..0fad510 100644
--- a/src/jdwp/jdwp_main.cc
+++ b/src/jdwp/jdwp_main.cc
@@ -457,6 +457,15 @@
   return os;
 }
 
+bool operator==(const JdwpLocation& lhs, const JdwpLocation& rhs) {
+  return lhs.idx == rhs.idx && lhs.methodId == rhs.methodId &&
+      lhs.classId == rhs.classId && lhs.typeTag == rhs.typeTag;
+}
+
+bool operator!=(const JdwpLocation& lhs, const JdwpLocation& rhs) {
+  return !(lhs == rhs);
+}
+
 std::ostream& operator<<(std::ostream& os, const JdwpTag& value) {
   switch (value) {
   case JT_ARRAY: os << "JT_ARRAY"; break;