Split dex_pc<->native_pc mapping table

First of 2 related CLs - this one moves to a split table, a future
CL will compress the table to save image space.

The current MappingTable mixes two flavors of entries: dex->pc and
pc(return address)->dex.  The problem is that we can have two
entries with the same native pc address but two different dex pcs.
The reason is that when we go from native pc to dex, the native
pc is actually the return address from the previous call, whereas
when we go from dex to native pc, the mapping refers to the first
native instruction of the sequence.

Previously, the first entry in the mapping table was the number
of subsequent entries.  That will remain the same, but now
the second entry will be a count of the number of entries in
the pc->dex section of the table.  The difference between the
two counts gives us the number of entries in the following dex->pc
section.

Change-Id: Ibadb96cb50bf1f93e079dff3832130b9f9782723
diff --git a/src/compiler/CompilerIR.h b/src/compiler/CompilerIR.h
index 56ae486..434320d 100644
--- a/src/compiler/CompilerIR.h
+++ b/src/compiler/CompilerIR.h
@@ -426,7 +426,18 @@
   AssemblerStatus assemblerStatus;    // Success or fix and retry
   int assemblerRetries;
   std::vector<uint8_t> codeBuffer;
-  std::vector<uint32_t> mappingTable;
+  /*
+   * Holds mapping from native PC to dex PC for safepoints where we may deoptimize.
+   * Native PC is on the return address of the safepointed operation.  Dex PC is for
+   * the instruction being executed at the safepoint.
+   */
+  std::vector<uint32_t> pc2dexMappingTable;
+  /*
+   * Holds mapping from Dex PC to native PC for catch entry points.  Native PC and Dex PC
+   * immediately preceed the instruction.
+   */
+  std::vector<uint32_t> dex2pcMappingTable;
+  std::vector<uint32_t> combinedMappingTable;
   std::vector<uint32_t> coreVmapTable;
   std::vector<uint32_t> fpVmapTable;
   std::vector<uint8_t> nativeGcMap;
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index 31d8aa5..09bc054 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -1216,9 +1216,8 @@
   }
   CompiledMethod* result =
       new CompiledMethod(cUnit->instructionSet, cUnit->codeBuffer,
-                         cUnit->frameSize, cUnit->coreSpillMask,
-                         cUnit->fpSpillMask, cUnit->mappingTable, vmapTable,
-                         cUnit->nativeGcMap);
+                         cUnit->frameSize, cUnit->coreSpillMask, cUnit->fpSpillMask,
+                         cUnit->combinedMappingTable, vmapTable, cUnit->nativeGcMap);
 
   VLOG(compiler) << "Compiled " << PrettyMethod(method_idx, dex_file)
      << " (" << (cUnit->codeBuffer.size() * sizeof(cUnit->codeBuffer[0]))
diff --git a/src/compiler/codegen/CodegenUtil.cc b/src/compiler/codegen/CodegenUtil.cc
index 4e39ffc..22aacc2 100644
--- a/src/compiler/codegen/CodegenUtil.cc
+++ b/src/compiler/codegen/CodegenUtil.cc
@@ -341,6 +341,9 @@
     case kPseudoSafepointPC:
       LOG(INFO) << "LsafepointPC_0x" << std::hex << lir->offset << "_" << lir->dalvikOffset << ":";
       break;
+    case kPseudoExportedPC:
+      LOG(INFO) << "LexportedPC_0x" << std::hex << lir->offset << "_" << lir->dalvikOffset << ":";
+      break;
     case kPseudoCaseLabel:
       LOG(INFO) << "LC" << (void*)lir << ": Case target 0x"
                 << std::hex << lir->operands[0] << "|" << std::dec <<
@@ -397,6 +400,23 @@
   }
 }
 
+/* Dump a mapping table */
+void dumpMappingTable(const char* table_name, const std::string& descriptor,
+                      const std::string& name, const std::string& signature,
+                      const std::vector<uint32_t>& v) {
+  if (v.size() > 0) {
+    std::string line(StringPrintf("\n  %s %s%s_%s_table[%zu] = {", table_name,
+                     descriptor.c_str(), name.c_str(), signature.c_str(), v.size()));
+    std::replace(line.begin(), line.end(), ';', '_');
+    LOG(INFO) << line;
+    for (uint32_t i = 0; i < v.size(); i+=2) {
+      line = StringPrintf("    {0x%05x, 0x%04x},", v[i], v[i+1]);
+      LOG(INFO) << line;
+    }
+    LOG(INFO) <<"  };\n\n";
+  }
+}
+
 /* Dump instructions and constant pool contents */
 void oatCodegenDump(CompilationUnit* cUnit)
 {
@@ -434,21 +454,9 @@
   std::string name(cUnit->dex_file->GetMethodName(method_id));
   std::string descriptor(cUnit->dex_file->GetMethodDeclaringClassDescriptor(method_id));
 
-  // Dump mapping table
-  if (cUnit->mappingTable.size() > 0) {
-    std::string
-        line(StringPrintf("\n  MappingTable %s%s_%s_mappingTable[%zu] = {",
-                          descriptor.c_str(), name.c_str(), signature.c_str(),
-                          cUnit->mappingTable.size()));
-    std::replace(line.begin(), line.end(), ';', '_');
-    LOG(INFO) << line;
-    for (uint32_t i = 0; i < cUnit->mappingTable.size(); i+=2) {
-      line = StringPrintf("    {0x%05x, 0x%04x},",
-                          cUnit->mappingTable[i], cUnit->mappingTable[i+1]);
-      LOG(INFO) << line;
-    }
-    LOG(INFO) <<"  };\n\n";
-  }
+  // Dump mapping tables
+  dumpMappingTable("PC2Dex_MappingTable", descriptor, name, signature, cUnit->pc2dexMappingTable);
+  dumpMappingTable("Dex2PC_MappingTable", descriptor, name, signature, cUnit->dex2pcMappingTable);
 }
 
 
@@ -465,7 +473,8 @@
   insn->operands[4] = op4;
   insn->target = target;
   oatSetupResourceMasks(insn);
-  if ((opcode == kPseudoTargetLabel) || (opcode == kPseudoSafepointPC)) {
+  if ((opcode == kPseudoTargetLabel) || (opcode == kPseudoSafepointPC) ||
+      (opcode == kPseudoExportedPC)) {
     // Always make labels scheduling barriers
     insn->useMask = insn->defMask = ENCODE_ALL;
   }
@@ -755,14 +764,27 @@
   return offset;
 }
 
-void createMappingTable(CompilationUnit* cUnit)
+void createMappingTables(CompilationUnit* cUnit)
 {
   for (LIR* tgtLIR = (LIR *) cUnit->firstLIRInsn; tgtLIR != NULL; tgtLIR = NEXT_LIR(tgtLIR)) {
     if (!tgtLIR->flags.isNop && (tgtLIR->opcode == kPseudoSafepointPC)) {
-      cUnit->mappingTable.push_back(tgtLIR->offset);
-      cUnit->mappingTable.push_back(tgtLIR->dalvikOffset);
+      cUnit->pc2dexMappingTable.push_back(tgtLIR->offset);
+      cUnit->pc2dexMappingTable.push_back(tgtLIR->dalvikOffset);
+    }
+    if (!tgtLIR->flags.isNop && (tgtLIR->opcode == kPseudoExportedPC)) {
+      cUnit->dex2pcMappingTable.push_back(tgtLIR->offset);
+      cUnit->dex2pcMappingTable.push_back(tgtLIR->dalvikOffset);
     }
   }
+  cUnit->combinedMappingTable.push_back(cUnit->pc2dexMappingTable.size() +
+                                        cUnit->dex2pcMappingTable.size());
+  cUnit->combinedMappingTable.push_back(cUnit->pc2dexMappingTable.size());
+  cUnit->combinedMappingTable.insert(cUnit->combinedMappingTable.end(),
+                                     cUnit->pc2dexMappingTable.begin(),
+                                     cUnit->pc2dexMappingTable.end());
+  cUnit->combinedMappingTable.insert(cUnit->combinedMappingTable.end(),
+                                     cUnit->dex2pcMappingTable.begin(),
+                                     cUnit->dex2pcMappingTable.end());
 }
 
 class NativePcToReferenceMapBuilder {
@@ -844,7 +866,7 @@
 };
 
 static void createNativeGcMap(CompilationUnit* cUnit) {
-  const std::vector<uint32_t>& mapping_table = cUnit->mappingTable;
+  const std::vector<uint32_t>& mapping_table = cUnit->pc2dexMappingTable;
   uint32_t max_native_offset = 0;
   for (size_t i = 0; i < mapping_table.size(); i += 2) {
     uint32_t native_offset = mapping_table[i + 0];
@@ -864,13 +886,8 @@
     uint32_t native_offset = mapping_table[i + 0];
     uint32_t dex_pc = mapping_table[i + 1];
     const uint8_t* references = dex_gc_map.FindBitMap(dex_pc, false);
-    if (references != NULL) {
-      native_gc_map_builder.AddEntry(native_offset, references);
-    } else {
-      // TODO: there is a mapping table entry but no reference bitmap. This happens because of
-      //       catch block entries. We should check that the dex_pc corresponds with a catch block
-      //       here.
-    }
+    CHECK(references != NULL) << "Missing ref for dex pc 0x" << std::hex << dex_pc;
+    native_gc_map_builder.AddEntry(native_offset, references);
   }
 }
 
@@ -981,7 +998,7 @@
   installFillArrayData(cUnit);
 
   // Create the mapping table and native offset to reference map.
-  createMappingTable(cUnit);
+  createMappingTables(cUnit);
 
   createNativeGcMap(cUnit);
 }
diff --git a/src/compiler/codegen/MethodBitcode.cc b/src/compiler/codegen/MethodBitcode.cc
index 682de7a..cff4ee5 100644
--- a/src/compiler/codegen/MethodBitcode.cc
+++ b/src/compiler/codegen/MethodBitcode.cc
@@ -2891,7 +2891,7 @@
     LIR* headLIR = NULL;
 
     if (blockType == kCatchBlock) {
-      headLIR = newLIR0(cUnit, kPseudoSafepointPC);
+      headLIR = newLIR0(cUnit, kPseudoExportedPC);
     }
 
     // Free temp registers and reset redundant store tracking */
diff --git a/src/compiler/codegen/MethodCodegenDriver.cc b/src/compiler/codegen/MethodCodegenDriver.cc
index 7227487..3a80d10 100644
--- a/src/compiler/codegen/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/MethodCodegenDriver.cc
@@ -870,9 +870,9 @@
 
   LIR* headLIR = NULL;
 
-  /* If this is a catch block, mark the beginning as a safepoint */
+  /* If this is a catch block, export the start address */
   if (bb->catchEntry) {
-    headLIR = newLIR0(cUnit, kPseudoSafepointPC);
+    headLIR = newLIR0(cUnit, kPseudoExportedPC);
   }
 
   /* Free temp registers and reset redundant store tracking */
diff --git a/src/compiler/codegen/arm/ArmLIR.h b/src/compiler/codegen/arm/ArmLIR.h
index 36a11f2..a40df20 100644
--- a/src/compiler/codegen/arm/ArmLIR.h
+++ b/src/compiler/codegen/arm/ArmLIR.h
@@ -291,6 +291,7 @@
  * Assemble.cc.
  */
 enum ArmOpcode {
+  kPseudoExportedPC = -18,
   kPseudoSafepointPC = -17,
   kPseudoIntrinsicRetry = -16,
   kPseudoSuspendTarget = -15,
diff --git a/src/compiler/codegen/mips/MipsLIR.h b/src/compiler/codegen/mips/MipsLIR.h
index c78cd8d..0f6226f 100644
--- a/src/compiler/codegen/mips/MipsLIR.h
+++ b/src/compiler/codegen/mips/MipsLIR.h
@@ -333,6 +333,7 @@
  * Assemble.cc.
  */
 enum MipsOpCode {
+  kPseudoExportedPC = -18,
   kPseudoSafepointPC = -17,
   kPseudoIntrinsicRetry = -16,
   kPseudoSuspendTarget = -15,
diff --git a/src/compiler/codegen/x86/X86LIR.h b/src/compiler/codegen/x86/X86LIR.h
index 43fc63c..d3e3da8 100644
--- a/src/compiler/codegen/x86/X86LIR.h
+++ b/src/compiler/codegen/x86/X86LIR.h
@@ -297,6 +297,7 @@
  * Assemble.cc.
  */
 enum X86OpCode {
+  kPseudoExportedPC = -18,
   kPseudoSafepointPC = -17,
   kPseudoIntrinsicRetry = -16,
   kPseudoSuspendTarget = -15,
diff --git a/src/exception_test.cc b/src/exception_test.cc
index 7303ac6..b82f8f7 100644
--- a/src/exception_test.cc
+++ b/src/exception_test.cc
@@ -47,7 +47,13 @@
       fake_code_.push_back(0x70 | i);
     }
 
-    fake_mapping_data_.push_back(2);  // first element is count of remaining elements
+    fake_mapping_data_.push_back(4);  // first element is count
+    fake_mapping_data_.push_back(4);  // total (non-length) elements
+    fake_mapping_data_.push_back(2);  // count of pc to dex elements
+                                      // ---  pc to dex table
+    fake_mapping_data_.push_back(3);  // offset 3
+    fake_mapping_data_.push_back(3);  // maps to dex offset 3
+                                      // ---  dex to pc table
     fake_mapping_data_.push_back(3);  // offset 3
     fake_mapping_data_.push_back(3);  // maps to dex offset 3
 
diff --git a/src/oatdump.cc b/src/oatdump.cc
index f08a498..c35d233 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -423,13 +423,18 @@
 
     uint32_t length = *raw_table;
     ++raw_table;
+    uint32_t pc_to_dex_entries = *raw_table;
+    ++raw_table;
 
     os << "\t\t{";
     for (size_t i = 0; i < length; i += 2) {
       const uint8_t* native_pc = reinterpret_cast<const uint8_t*>(code) + raw_table[i];
       uint32_t dex_pc = raw_table[i + 1];
       os << StringPrintf("%p -> 0x%04x", native_pc, dex_pc);
-      if (i + 2 < length) {
+      if (i + 2 == pc_to_dex_entries) {
+        // Separate the pc -> dex from dex -> pc sections
+        os << "}\n\t\t{";
+      } else if (i + 2 < length) {
         os << ", ";
       }
     }
diff --git a/src/object.cc b/src/object.cc
index 284f221..90342ff 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -514,14 +514,37 @@
   return pc - reinterpret_cast<uintptr_t>(GetOatCode(this));
 }
 
-uint32_t AbstractMethod::ToDexPc(const uintptr_t pc) const {
+// Find the lowest-address native safepoint pc for a given dex pc
+uint32_t AbstractMethod::ToFirstNativeSafepointPc(const uintptr_t dex_pc) const {
 #if !defined(ART_USE_LLVM_COMPILER)
-  const uint32_t* mapping_table = GetMappingTable();
+  const uint32_t* mapping_table = GetPcToDexMappingTable();
   if (mapping_table == NULL) {
     DCHECK(IsNative() || IsCalleeSaveMethod() || IsProxyMethod()) << PrettyMethod(this);
     return DexFile::kDexNoIndex;   // Special no mapping case
   }
-  size_t mapping_table_length = GetMappingTableLength();
+  size_t mapping_table_length = GetPcToDexMappingTableLength();
+  for (size_t i = 0; i < mapping_table_length; i += 2) {
+    if (mapping_table[i + 1] == dex_pc) {
+      return mapping_table[i] + reinterpret_cast<uintptr_t>(GetOatCode(this));
+    }
+  }
+  LOG(FATAL) << "Failed to find native offset for dex pc 0x" << std::hex << dex_pc
+             << " in " << PrettyMethod(this);
+  return 0;
+#else
+  // Compiler LLVM doesn't use the machine pc, we just use dex pc instead.
+  return static_cast<uint32_t>(dex_pc);
+#endif
+}
+
+uint32_t AbstractMethod::ToDexPc(const uintptr_t pc) const {
+#if !defined(ART_USE_LLVM_COMPILER)
+  const uint32_t* mapping_table = GetPcToDexMappingTable();
+  if (mapping_table == NULL) {
+    DCHECK(IsNative() || IsCalleeSaveMethod() || IsProxyMethod()) << PrettyMethod(this);
+    return DexFile::kDexNoIndex;   // Special no mapping case
+  }
+  size_t mapping_table_length = GetPcToDexMappingTableLength();
   uint32_t sought_offset = pc - reinterpret_cast<uintptr_t>(GetOatCode(this));
   for (size_t i = 0; i < mapping_table_length; i += 2) {
     if (mapping_table[i] == sought_offset) {
@@ -538,12 +561,12 @@
 }
 
 uintptr_t AbstractMethod::ToNativePc(const uint32_t dex_pc) const {
-  const uint32_t* mapping_table = GetMappingTable();
+  const uint32_t* mapping_table = GetDexToPcMappingTable();
   if (mapping_table == NULL) {
     DCHECK_EQ(dex_pc, 0U);
     return 0;   // Special no mapping/pc == 0 case
   }
-  size_t mapping_table_length = GetMappingTableLength();
+  size_t mapping_table_length = GetDexToPcMappingTableLength();
   for (size_t i = 0; i < mapping_table_length; i += 2) {
     uint32_t map_offset = mapping_table[i];
     uint32_t map_dex_offset = mapping_table[i + 1];
@@ -551,7 +574,8 @@
       return reinterpret_cast<uintptr_t>(GetOatCode(this)) + map_offset;
     }
   }
-  LOG(FATAL) << "Looking up Dex PC not contained in method";
+  LOG(FATAL) << "Looking up Dex PC not contained in method, 0x" << std::hex << dex_pc
+             << " in " << PrettyMethod(this);
   return 0;
 }
 
diff --git a/src/object.h b/src/object.h
index 947b77d..5fccb04 100644
--- a/src/object.h
+++ b/src/object.h
@@ -729,14 +729,40 @@
     return map + 1;
   }
 
-  uint32_t GetMappingTableLength() const {
+  uint32_t GetPcToDexMappingTableLength() const {
     const uint32_t* map = GetMappingTableRaw();
     if (map == NULL) {
       return 0;
     }
-    return *map;
+    return map[2];
   }
 
+  const uint32_t* GetPcToDexMappingTable() const {
+    const uint32_t* map = GetMappingTableRaw();
+    if (map == NULL) {
+      return map;
+    }
+    return map + 3;
+  }
+
+
+  uint32_t GetDexToPcMappingTableLength() const {
+    const uint32_t* map = GetMappingTableRaw();
+    if (map == NULL) {
+      return 0;
+    }
+    return map[1] - map[2];
+  }
+
+  const uint32_t* GetDexToPcMappingTable() const {
+    const uint32_t* map = GetMappingTableRaw();
+    if (map == NULL) {
+      return map;
+    }
+    return map + 3 + map[2];
+  }
+
+
   const uint32_t* GetMappingTableRaw() const {
     return GetFieldPtr<const uint32_t*>(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, mapping_table_), false);
   }
@@ -922,6 +948,10 @@
   // Converts a dex PC to a native PC.
   uintptr_t ToNativePc(const uint32_t dex_pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Converts a dex PC to the first corresponding safepoint PC.
+  uintptr_t ToFirstNativeSafepointPc(const uint32_t dex_pc)
+      const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Find the catch block for the given exception type and dex_pc
   uint32_t FindCatchBlock(Class* exception_type, uint32_t dex_pc) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/test/ReferenceMap/stack_walk_refmap_jni.cc b/test/ReferenceMap/stack_walk_refmap_jni.cc
index 0b6cd7e..a9dfbac 100644
--- a/test/ReferenceMap/stack_walk_refmap_jni.cc
+++ b/test/ReferenceMap/stack_walk_refmap_jni.cc
@@ -75,31 +75,31 @@
     // we know the Dex registers with live reference values. Assert that what we
     // find is what is expected.
     if (m_name.compare("f") == 0) {
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x03U)));
+      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToFirstNativeSafepointPc(0x03U)));
       CHECK(ref_bitmap);
       CHECK_REGS_CONTAIN_REFS(8);  // v8: this
 
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x06U)));
+      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToFirstNativeSafepointPc(0x06U)));
       CHECK(ref_bitmap);
       CHECK_REGS_CONTAIN_REFS(8, 1);  // v8: this, v1: x
 
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x08U)));
+      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToFirstNativeSafepointPc(0x08U)));
       CHECK(ref_bitmap);
       CHECK_REGS_CONTAIN_REFS(8, 3, 1);  // v8: this, v3: y, v1: x
 
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x0cU)));
+      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToFirstNativeSafepointPc(0x0cU)));
       CHECK(ref_bitmap);
       CHECK_REGS_CONTAIN_REFS(8, 3, 1);  // v8: this, v3: y, v1: x
 
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x0eU)));
+      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToFirstNativeSafepointPc(0x0eU)));
       CHECK(ref_bitmap);
       CHECK_REGS_CONTAIN_REFS(8, 3, 1);  // v8: this, v3: y, v1: x
 
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x10U)));
+      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToFirstNativeSafepointPc(0x10U)));
       CHECK(ref_bitmap);
       CHECK_REGS_CONTAIN_REFS(8, 3, 1);  // v8: this, v3: y, v1: x
 
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x13U)));
+      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToFirstNativeSafepointPc(0x13U)));
       CHECK(ref_bitmap);
       // v2 is added because of the instruction at DexPC 0024. Object merges with 0 is Object. See:
       //   0024: move-object v3, v2
@@ -107,49 +107,49 @@
       // Detaled dex instructions for ReferenceMap.java are at the end of this function.
       CHECK_REGS_CONTAIN_REFS(8, 3, 2, 1);  // v8: this, v3: y, v2: y, v1: x
 
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x18U)));
+      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToFirstNativeSafepointPc(0x18U)));
       CHECK(ref_bitmap);
       CHECK_REGS_CONTAIN_REFS(8, 2, 1, 0);  // v8: this, v2: y, v1: x, v0: ex
 
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x1aU)));
+      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToFirstNativeSafepointPc(0x1aU)));
       CHECK(ref_bitmap);
       CHECK_REGS_CONTAIN_REFS(8, 5, 2, 1, 0);  // v8: this, v5: x[1], v2: y, v1: x, v0: ex
 
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x1dU)));
+      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToFirstNativeSafepointPc(0x1dU)));
       CHECK(ref_bitmap);
       CHECK_REGS_CONTAIN_REFS(8, 5, 2, 1, 0);  // v8: this, v5: x[1], v2: y, v1: x, v0: ex
 
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x1fU)));
+      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToFirstNativeSafepointPc(0x1fU)));
       CHECK(ref_bitmap);
       // v5 is removed from the root set because there is a "merge" operation.
       // See 0015: if-nez v2, 001f.
       CHECK_REGS_CONTAIN_REFS(8, 2, 1, 0);  // v8: this, v2: y, v1: x, v0: ex
 
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x21U)));
+      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToFirstNativeSafepointPc(0x21U)));
       CHECK(ref_bitmap);
       CHECK_REGS_CONTAIN_REFS(8, 2, 1, 0);  // v8: this, v2: y, v1: x, v0: ex
 
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x25U)));
+      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToFirstNativeSafepointPc(0x25U)));
       CHECK(ref_bitmap);
       CHECK_REGS_CONTAIN_REFS(8, 3, 2, 1, 0);  // v8: this, v3: y, v2: y, v1: x, v0: ex
 
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x27U)));
+      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToFirstNativeSafepointPc(0x27U)));
       CHECK(ref_bitmap);
       CHECK_REGS_CONTAIN_REFS(8, 4, 2, 1);  // v8: this, v4: ex, v2: y, v1: x
 
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x29U)));
+      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToFirstNativeSafepointPc(0x29U)));
       CHECK(ref_bitmap);
       CHECK_REGS_CONTAIN_REFS(8, 4, 2, 1);  // v8: this, v4: ex, v2: y, v1: x
 
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x2cU)));
+      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToFirstNativeSafepointPc(0x2cU)));
       CHECK(ref_bitmap);
       CHECK_REGS_CONTAIN_REFS(8, 4, 2, 1);  // v8: this, v4: ex, v2: y, v1: x
 
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x2fU)));
+      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToFirstNativeSafepointPc(0x2fU)));
       CHECK(ref_bitmap);
       CHECK_REGS_CONTAIN_REFS(8, 4, 3, 2, 1);  // v8: this, v4: ex, v3: y, v2: y, v1: x
 
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x32U)));
+      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToFirstNativeSafepointPc(0x32U)));
       CHECK(ref_bitmap);
       CHECK_REGS_CONTAIN_REFS(8, 3, 2, 1, 0);  // v8: this, v3: y, v2: y, v1: x, v0: ex
     }