NativePcOffsetToReferenceMap

Rather than translate a native PC to a Dex PC and then to the reference
bitmap, just go straight from the native PC to the reference bitmap.
Encode the native PC offsets using a hash rather than linearly
searching.

Change-Id: Iee1073d93c941c0a31f639e5f23cea9e9f747bee
diff --git a/src/thread.cc b/src/thread.cc
index 935b05c..eaa6683 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -31,6 +31,7 @@
 #include "class_linker.h"
 #include "class_loader.h"
 #include "debugger.h"
+#include "gc_map.h"
 #include "heap.h"
 #include "jni_internal.h"
 #include "monitor.h"
@@ -47,7 +48,6 @@
 #include "stack_indirect_reference_table.h"
 #include "thread_list.h"
 #include "utils.h"
-#include "verifier/gc_map.h"
 #include "well_known_classes.h"
 
 namespace art {
@@ -1558,7 +1558,7 @@
         // Unwind stack when an exception occurs during method tracing
         if (UNLIKELY(method_tracing_active_ && IsTraceExitPc(GetCurrentQuickFramePc()))) {
           uintptr_t pc = TraceMethodUnwindFromCode(Thread::Current());
-          dex_pc = method->ToDexPC(pc);
+          dex_pc = method->ToDexPc(pc);
         } else {
           dex_pc = GetDexPc();
         }
@@ -1568,7 +1568,7 @@
       uint32_t found_dex_pc = method->FindCatchBlock(to_find_, dex_pc);
       if (found_dex_pc != DexFile::kDexNoIndex) {
         handler_dex_pc_ = found_dex_pc;
-        handler_quick_frame_pc_ = method->ToNativePC(found_dex_pc);
+        handler_quick_frame_pc_ = method->ToNativePc(found_dex_pc);
         handler_quick_frame_ = GetCurrentQuickFrame();
         return false;  // End stack walk.
       }
@@ -1712,49 +1712,50 @@
       Method* m = GetMethod();
       // Process register map (which native and runtime methods don't have)
       if (!m->IsNative() && !m->IsRuntimeMethod() && !m->IsProxyMethod()) {
-        const uint8_t* gc_map = m->GetGcMap();
-        CHECK(gc_map != NULL) << PrettyMethod(m);
-        uint32_t gc_map_length = m->GetGcMapLength();
-        CHECK_NE(0U, gc_map_length) << PrettyMethod(m);
-        verifier::DexPcToReferenceMap map(gc_map, gc_map_length);
-        const uint8_t* reg_bitmap = map.FindBitMap(GetDexPc());
-        CHECK(reg_bitmap != NULL);
-        const VmapTable vmap_table(m->GetVmapTableRaw());
-        const DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
+        const uint8_t* native_gc_map = m->GetNativeGcMap();
+        CHECK(native_gc_map != NULL) << PrettyMethod(m);
+        mh_.ChangeMethod(m);
+        const DexFile::CodeItem* code_item = mh_.GetCodeItem();
         DCHECK(code_item != NULL) << PrettyMethod(m); // Can't be NULL or how would we compile its instructions?
-        uint32_t core_spills = m->GetCoreSpillMask();
-        uint32_t fp_spills = m->GetFpSpillMask();
-        size_t frame_size = m->GetFrameSizeInBytes();
-        // For all dex registers in the bitmap
+        NativePcOffsetToReferenceMap map(native_gc_map);
         size_t num_regs = std::min(map.RegWidth() * 8,
                                    static_cast<size_t>(code_item->registers_size_));
-        Method** cur_quick_frame = GetCurrentQuickFrame();
-        DCHECK(cur_quick_frame != NULL);
-        for (size_t reg = 0; reg < num_regs; ++reg) {
-          // Does this register hold a reference?
-          if (TestBitmap(reg, reg_bitmap)) {
-            uint32_t vmap_offset;
-            Object* ref;
-            if (vmap_table.IsInContext(reg, vmap_offset)) {
-              // Compute the register we need to load from the context
-              uint32_t spill_mask = core_spills;
-              CHECK_LT(vmap_offset, static_cast<uint32_t>(__builtin_popcount(spill_mask)));
-              uint32_t matches = 0;
-              uint32_t spill_shifts = 0;
-              while (matches != (vmap_offset + 1)) {
-                DCHECK_NE(spill_mask, 0u);
-                matches += spill_mask & 1;  // Add 1 if the low bit is set
-                spill_mask >>= 1;
-                spill_shifts++;
+        if (num_regs > 0) {
+          const uint8_t* reg_bitmap = map.FindBitMap(GetNativePcOffset());
+          DCHECK(reg_bitmap != NULL);
+          const VmapTable vmap_table(m->GetVmapTableRaw());
+          uint32_t core_spills = m->GetCoreSpillMask();
+          uint32_t fp_spills = m->GetFpSpillMask();
+          size_t frame_size = m->GetFrameSizeInBytes();
+          // For all dex registers in the bitmap
+          Method** cur_quick_frame = GetCurrentQuickFrame();
+          DCHECK(cur_quick_frame != NULL);
+          for (size_t reg = 0; reg < num_regs; ++reg) {
+            // Does this register hold a reference?
+            if (TestBitmap(reg, reg_bitmap)) {
+              uint32_t vmap_offset;
+              Object* ref;
+              if (vmap_table.IsInContext(reg, vmap_offset)) {
+                // Compute the register we need to load from the context
+                uint32_t spill_mask = core_spills;
+                CHECK_LT(vmap_offset, static_cast<uint32_t>(__builtin_popcount(spill_mask)));
+                uint32_t matches = 0;
+                uint32_t spill_shifts = 0;
+                while (matches != (vmap_offset + 1)) {
+                  DCHECK_NE(spill_mask, 0u);
+                  matches += spill_mask & 1;  // Add 1 if the low bit is set
+                  spill_mask >>= 1;
+                  spill_shifts++;
+                }
+                spill_shifts--;  // wind back one as we want the last match
+                ref = reinterpret_cast<Object*>(GetGPR(spill_shifts));
+              } else {
+                ref = reinterpret_cast<Object*>(GetVReg(cur_quick_frame, code_item, core_spills,
+                                                        fp_spills, frame_size, reg));
               }
-              spill_shifts--;  // wind back one as we want the last match
-              ref = reinterpret_cast<Object*>(GetGPR(spill_shifts));
-            } else {
-              ref = reinterpret_cast<Object*>(GetVReg(cur_quick_frame, code_item, core_spills,
-                                                      fp_spills, frame_size, reg));
-            }
-            if (ref != NULL) {
-              root_visitor_(ref, arg_);
+              if (ref != NULL) {
+                root_visitor_(ref, arg_);
+              }
             }
           }
         }
@@ -1768,10 +1769,12 @@
     return ((reg_vector[reg / 8] >> (reg % 8)) & 0x01) != 0;
   }
 
-  // Call-back when we visit a root
+  // Call-back when we visit a root.
   Heap::RootVisitor* root_visitor_;
-  // Argument to call-back
+  // Argument to call-back.
   void* arg_;
+  // A method helper we keep around to avoid dex file/cache re-computations.
+  MethodHelper mh_;
 };
 
 void Thread::VisitRoots(Heap::RootVisitor* visitor, void* arg) {