Delete ArtMethod gc_map_ field

Moved the gc_map field from OatMethod to OatQuickMethodHeader.
Deleted the ArtMethod gc_map_ field.

Bug: 17643507

Change-Id: Ifa0470c3e4c2f8a319744464d94c6838b76b3d48
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 5e4623d..b59ab13 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -142,22 +142,12 @@
 CommonCompilerTest::CommonCompilerTest() {}
 CommonCompilerTest::~CommonCompilerTest() {}
 
-OatFile::OatMethod CommonCompilerTest::CreateOatMethod(const void* code, const uint8_t* gc_map) {
+OatFile::OatMethod CommonCompilerTest::CreateOatMethod(const void* code) {
   CHECK(code != nullptr);
-  const byte* base;
-  uint32_t code_offset, gc_map_offset;
-  if (gc_map == nullptr) {
-    base = reinterpret_cast<const byte*>(code);  // Base of data points at code.
-    base -= kPointerSize;  // Move backward so that code_offset != 0.
-    code_offset = kPointerSize;
-    gc_map_offset = 0;
-  } else {
-    // TODO: 64bit support.
-    base = nullptr;  // Base of data in oat file, ie 0.
-    code_offset = PointerToLowMemUInt32(code);
-    gc_map_offset = PointerToLowMemUInt32(gc_map);
-  }
-  return OatFile::OatMethod(base, code_offset, gc_map_offset);
+  const byte* base = reinterpret_cast<const byte*>(code);  // Base of data points at code.
+  base -= kPointerSize;  // Move backward so that code_offset != 0.
+  uint32_t  code_offset = kPointerSize;
+  return OatFile::OatMethod(base, code_offset);
 }
 
 void CommonCompilerTest::MakeExecutable(mirror::ArtMethod* method) {
@@ -183,14 +173,18 @@
       const std::vector<uint8_t>& mapping_table = compiled_method->GetMappingTable();
       uint32_t mapping_table_offset = mapping_table.empty() ? 0u
           : sizeof(OatQuickMethodHeader) + vmap_table.size() + mapping_table.size();
-      OatQuickMethodHeader method_header(mapping_table_offset, vmap_table_offset,
+      const std::vector<uint8_t>& gc_map = compiled_method->GetGcMap();
+      uint32_t gc_map_offset = gc_map.empty() ? 0u
+          : sizeof(OatQuickMethodHeader) + vmap_table.size() + mapping_table.size() + gc_map.size();
+      OatQuickMethodHeader method_header(mapping_table_offset, vmap_table_offset, gc_map_offset,
                                          compiled_method->GetFrameSizeInBytes(),
                                          compiled_method->GetCoreSpillMask(),
                                          compiled_method->GetFpSpillMask(), code_size);
 
       header_code_and_maps_chunks_.push_back(std::vector<uint8_t>());
       std::vector<uint8_t>* chunk = &header_code_and_maps_chunks_.back();
-      size_t size = sizeof(method_header) + code_size + vmap_table.size() + mapping_table.size();
+      size_t size = sizeof(method_header) + code_size + vmap_table.size() + mapping_table.size() +
+          gc_map.size();
       size_t code_offset = compiled_method->AlignCode(size - code_size);
       size_t padding = code_offset - (size - code_size);
       chunk->reserve(padding + size);
@@ -198,6 +192,7 @@
       memcpy(&(*chunk)[0], &method_header, sizeof(method_header));
       chunk->insert(chunk->begin(), vmap_table.begin(), vmap_table.end());
       chunk->insert(chunk->begin(), mapping_table.begin(), mapping_table.end());
+      chunk->insert(chunk->begin(), gc_map.begin(), gc_map.end());
       chunk->insert(chunk->begin(), padding, 0);
       chunk->insert(chunk->end(), code->begin(), code->end());
       CHECK_EQ(padding + size, chunk->size());
@@ -210,7 +205,7 @@
     const void* method_code = CompiledMethod::CodePointer(code_ptr,
                                                           compiled_method->GetInstructionSet());
     LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code;
-    OatFile::OatMethod oat_method = CreateOatMethod(method_code, nullptr);
+    OatFile::OatMethod oat_method = CreateOatMethod(method_code);
     oat_method.LinkMethod(method);
     method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
   } else {
@@ -222,13 +217,13 @@
 #else
       const void* method_code = GetQuickToInterpreterBridge();
 #endif
-      OatFile::OatMethod oat_method = CreateOatMethod(method_code, nullptr);
+      OatFile::OatMethod oat_method = CreateOatMethod(method_code);
       oat_method.LinkMethod(method);
       method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge);
     } else {
       const void* method_code = reinterpret_cast<void*>(art_quick_generic_jni_trampoline);
 
-      OatFile::OatMethod oat_method = CreateOatMethod(method_code, nullptr);
+      OatFile::OatMethod oat_method = CreateOatMethod(method_code);
       oat_method.LinkMethod(method);
       method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
     }
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index df06b71..dd25dff 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -42,7 +42,7 @@
   ~CommonCompilerTest();
 
   // Create an OatMethod based on pointers (for unit tests).
-  OatFile::OatMethod CreateOatMethod(const void* code, const uint8_t* gc_map);
+  OatFile::OatMethod CreateOatMethod(const void* code);
 
   void MakeExecutable(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 193be15..dedbf8d 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -1139,7 +1139,6 @@
   copy->SetEntryPointFromJniPtrSize<kVerifyNone>(orig->GetEntryPointFromJni(), target_ptr_size_);
   copy->SetEntryPointFromQuickCompiledCodePtrSize<kVerifyNone>(
       orig->GetEntryPointFromQuickCompiledCode(), target_ptr_size_);
-  copy->SetNativeGcMapPtrSize<kVerifyNone>(orig->GetNativeGcMap(), target_ptr_size_);
 
   // The resolution method has a special trampoline to call.
   Runtime* runtime = Runtime::Current();
@@ -1208,11 +1207,6 @@
         // Note this is not the code_ pointer, that is handled above.
         copy->SetEntryPointFromJniPtrSize<kVerifyNone>(GetOatAddress(jni_dlsym_lookup_offset_),
                                                        target_ptr_size_);
-      } else {
-        // Normal (non-abstract non-native) methods have various tables to relocate.
-        uint32_t native_gc_map_offset = orig->GetOatNativeGcMapOffset();
-        const uint8_t* native_gc_map = GetOatAddress(native_gc_map_offset);
-        copy->SetNativeGcMapPtrSize<kVerifyNone>(native_gc_map, target_ptr_size_);
       }
 
       // Interpreter entrypoint:
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 5bf19ed..a32fac1 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -143,15 +143,18 @@
   }
 
   static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE {
-    return oat_class->method_offsets_[method_offsets_index].gc_map_offset_;
+    uint32_t offset = oat_class->method_headers_[method_offsets_index].gc_map_offset_;
+    return offset == 0u ? 0u :
+        (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
   }
 
   static void SetOffset(OatClass* oat_class, size_t method_offsets_index, uint32_t offset)
       ALWAYS_INLINE {
-    oat_class->method_offsets_[method_offsets_index].gc_map_offset_ = offset;
+    oat_class->method_headers_[method_offsets_index].gc_map_offset_ =
+        (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
   }
 
-  static const char* Name() ALWAYS_INLINE {
+  static const char* Name() {
     return "GC map";
   }
 };
@@ -173,7 +176,7 @@
         (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
   }
 
-  static const char* Name() ALWAYS_INLINE {
+  static const char* Name() {
     return "mapping table";
   }
 };
@@ -195,7 +198,7 @@
         (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
   }
 
-  static const char* Name() ALWAYS_INLINE {
+  static const char* Name() {
     return "vmap table";
   }
 };
@@ -374,6 +377,7 @@
         OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
         uint32_t mapping_table_offset = method_header->mapping_table_offset_;
         uint32_t vmap_table_offset = method_header->vmap_table_offset_;
+        uint32_t gc_map_offset = method_header->gc_map_offset_;
         // The code offset was 0 when the mapping/vmap table offset was set, so it's set
         // to 0-offset and we need to adjust it by code_offset.
         uint32_t code_offset = quick_code_offset - thumb_offset;
@@ -385,12 +389,16 @@
           vmap_table_offset += code_offset;
           DCHECK_LT(vmap_table_offset, code_offset);
         }
+        if (gc_map_offset != 0u) {
+          gc_map_offset += code_offset;
+          DCHECK_LT(gc_map_offset, code_offset);
+        }
         uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
         uint32_t core_spill_mask = compiled_method->GetCoreSpillMask();
         uint32_t fp_spill_mask = compiled_method->GetFpSpillMask();
         *method_header = OatQuickMethodHeader(mapping_table_offset, vmap_table_offset,
-                                              frame_size_in_bytes, core_spill_mask, fp_spill_mask,
-                                              code_size);
+                                              gc_map_offset, frame_size_in_bytes, core_spill_mask,
+                                              fp_spill_mask, code_size);
 
         // Update checksum if this wasn't a duplicate.
         if (!deduped) {
@@ -533,7 +541,7 @@
     OatClass* oat_class = writer_->oat_classes_[oat_class_index_];
     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
 
-    OatMethodOffsets offsets(0u, 0u);
+    OatMethodOffsets offsets(0u);
     if (compiled_method != nullptr) {
       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
       offsets = oat_class->method_offsets_[method_offsets_index_];
@@ -544,7 +552,7 @@
     InvokeType invoke_type = it.GetMethodInvokeType(dex_file_->GetClassDef(class_def_index_));
     // Unchecked as we hold mutator_lock_ on entry.
     ScopedObjectAccessUnchecked soa(Thread::Current());
-    StackHandleScope<2> hs(soa.Self());
+    StackHandleScope<1> hs(soa.Self());
     Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->FindDexCache(*dex_file_)));
     mirror::ArtMethod* method = linker->ResolveMethod(*dex_file_, it.GetMemberIndex(), dex_cache,
                                                       NullHandle<mirror::ClassLoader>(),
@@ -553,7 +561,6 @@
     CHECK(method != NULL) << PrettyMethod(it.GetMemberIndex(), *dex_file_, true);
     // Portable code offsets are set by ElfWriterMclinker::FixupCompiledCodeOffset after linking.
     method->SetQuickOatCodeOffset(offsets.code_offset_);
-    method->SetOatNativeGcMapOffset(offsets.gc_map_offset_);
 
     return true;
   }
@@ -605,7 +612,8 @@
                    offset_ + sizeof(OatQuickMethodHeader) + compiled_method->CodeDelta())
             << PrettyMethod(it.GetMemberIndex(), *dex_file_);
         if (method_offsets.code_offset_ >= offset_) {
-          const OatQuickMethodHeader& method_header = oat_class->method_headers_[method_offsets_index_];
+          const OatQuickMethodHeader& method_header =
+              oat_class->method_headers_[method_offsets_index_];
           if (!out->WriteFully(&method_header, sizeof(method_header))) {
             ReportWriteFailure("method header", it);
             return false;
@@ -642,7 +650,7 @@
 class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor {
  public:
   WriteMapMethodVisitor(OatWriter* writer, OutputStream* out, const size_t file_offset,
-                          size_t relative_offset)
+                        size_t relative_offset)
     : OatDexMethodVisitor(writer, relative_offset),
       out_(out),
       file_offset_(file_offset) {
@@ -664,7 +672,8 @@
       size_t map_size = map->size() * sizeof((*map)[0]);
       DCHECK((map_size == 0u && map_offset == 0u) ||
             (map_size != 0u && map_offset != 0u && map_offset <= offset_))
-          << PrettyMethod(it.GetMemberIndex(), *dex_file_);
+          << map_size << " " << map_offset << " " << offset_ << " "
+          << PrettyMethod(it.GetMemberIndex(), *dex_file_) << " for " << DataAccess::Name();
       if (map_size != 0u && map_offset == offset_) {
         if (UNLIKELY(!out->WriteFully(&(*map)[0], map_size))) {
           ReportWriteFailure(it);
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index d638b29..4734a9c 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -355,7 +355,7 @@
     offsets_.insert(code_offset);
     offsets_.insert(oat_method.GetMappingTableOffset());
     offsets_.insert(oat_method.GetVmapTableOffset());
-    offsets_.insert(oat_method.GetNativeGcMapOffset());
+    offsets_.insert(oat_method.GetGcMapOffset());
   }
 
   bool DumpOatDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) {
@@ -500,9 +500,9 @@
 
       *indent2_os << "gc_map: ";
       if (options_->absolute_addresses_) {
-        *indent2_os << StringPrintf("%p ", oat_method.GetNativeGcMap());
+        *indent2_os << StringPrintf("%p ", oat_method.GetGcMap());
       }
-      uint32_t gc_map_offset = oat_method.GetNativeGcMapOffset();
+      uint32_t gc_map_offset = oat_method.GetGcMapOffset();
       *indent2_os << StringPrintf("(offset=0x%08x)\n", gc_map_offset);
       if (gc_map_offset > oat_file_.Size()) {
         *indent2_os << StringPrintf("WARNING: "
@@ -744,7 +744,7 @@
   }
   void DumpGcMap(std::ostream& os, const OatFile::OatMethod& oat_method,
                  const DexFile::CodeItem* code_item) {
-    const uint8_t* gc_map_raw = oat_method.GetNativeGcMap();
+    const uint8_t* gc_map_raw = oat_method.GetGcMap();
     if (gc_map_raw == nullptr) {
       return;  // No GC map.
     }
@@ -822,7 +822,7 @@
 
   void DumpGcMapAtNativePcOffset(std::ostream& os, const OatFile::OatMethod& oat_method,
                                  const DexFile::CodeItem* code_item, size_t native_pc_offset) {
-    const uint8_t* gc_map_raw = oat_method.GetNativeGcMap();
+    const uint8_t* gc_map_raw = oat_method.GetGcMap();
     if (gc_map_raw != nullptr) {
       NativePcOffsetToReferenceMap map(gc_map_raw);
       if (map.HasEntry(native_pc_offset)) {
@@ -1314,8 +1314,7 @@
       mirror::ArtMethod* method = obj->AsArtMethod();
       if (method->IsNative()) {
         // TODO: portable dumping.
-        DCHECK(method->GetNativeGcMapPtrSize(image_pointer_size) == nullptr)
-            << PrettyMethod(method);
+        DCHECK(method->GetNativeGcMap(image_pointer_size) == nullptr) << PrettyMethod(method);
         DCHECK(method->GetMappingTable(image_pointer_size) == nullptr) << PrettyMethod(method);
         bool first_occurrence;
         const void* quick_oat_code = state->GetQuickOatCodeBegin(method);
@@ -1331,8 +1330,7 @@
       } else if (method->IsAbstract() || method->IsCalleeSaveMethod() ||
           method->IsResolutionMethod() || method->IsImtConflictMethod() ||
           method->IsImtUnimplementedMethod() || method->IsClassInitializer()) {
-        DCHECK(method->GetNativeGcMapPtrSize(image_pointer_size) == nullptr)
-            << PrettyMethod(method);
+        DCHECK(method->GetNativeGcMap(image_pointer_size) == nullptr) << PrettyMethod(method);
         DCHECK(method->GetMappingTable(image_pointer_size) == nullptr) << PrettyMethod(method);
       } else {
         const DexFile::CodeItem* code_item = method->GetCodeItem();
@@ -1340,8 +1338,8 @@
         state->stats_.dex_instruction_bytes += dex_instruction_bytes;
 
         bool first_occurrence;
-        size_t gc_map_bytes = state->ComputeOatSize(
-            method->GetNativeGcMapPtrSize(image_pointer_size), &first_occurrence);
+        size_t gc_map_bytes =
+            state->ComputeOatSize(method->GetNativeGcMap(image_pointer_size), &first_occurrence);
         if (first_occurrence) {
           state->stats_.gc_map_bytes += gc_map_bytes;
         }
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 610ff06..b046ea1 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -558,12 +558,6 @@
     copy->SetEntryPointFromJniPtrSize(reinterpret_cast<void*>(native_method + delta_),
                                       pointer_size);
   }
-
-  uintptr_t native_gc_map = reinterpret_cast<uintptr_t>(
-      object->GetNativeGcMapPtrSize(pointer_size));
-  if (native_gc_map != 0) {
-    copy->SetNativeGcMapPtrSize(reinterpret_cast<uint8_t*>(native_gc_map + delta_), pointer_size);
-  }
 }
 
 bool PatchOat::Patch(File* input_oat, off_t delta, File* output_oat, TimingLogger* timings,
diff --git a/runtime/entrypoints/portable/portable_thread_entrypoints.cc b/runtime/entrypoints/portable/portable_thread_entrypoints.cc
index 23e1c36..46dfa3a 100644
--- a/runtime/entrypoints/portable/portable_thread_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_thread_entrypoints.cc
@@ -35,7 +35,7 @@
       uint32_t dex_pc = cur_frame->GetDexPC();
       ShadowFrame* new_frame = ShadowFrame::Create(num_regs, NULL, method, dex_pc);
 
-      const uint8_t* gc_map = method->GetNativeGcMap();
+      const uint8_t* gc_map = method->GetNativeGcMap(sizeof(void*));
       verifier::DexPcToReferenceMap dex_gc_map(gc_map);
       const uint8_t* reg_bitmap = dex_gc_map.FindBitMap(dex_pc);
       for (size_t reg = 0; reg < num_regs; ++reg) {
diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc
index 99633a3..fd3b65e 100644
--- a/runtime/exception_test.cc
+++ b/runtime/exception_test.cc
@@ -76,7 +76,8 @@
     const std::vector<uint8_t>& fake_mapping_data = fake_mapping_data_.GetData();
     uint32_t vmap_table_offset = sizeof(OatQuickMethodHeader) + fake_vmap_table_data.size();
     uint32_t mapping_table_offset = vmap_table_offset + fake_mapping_data.size();
-    OatQuickMethodHeader method_header(mapping_table_offset, vmap_table_offset,
+    uint32_t gc_map_offset = mapping_table_offset + fake_gc_map_.size();
+    OatQuickMethodHeader method_header(mapping_table_offset, vmap_table_offset, gc_map_offset,
                                        4 * kPointerSize, 0u, 0u, code_size);
     fake_header_code_and_maps_.resize(sizeof(method_header));
     memcpy(&fake_header_code_and_maps_[0], &method_header, sizeof(method_header));
@@ -84,6 +85,8 @@
                                       fake_vmap_table_data.begin(), fake_vmap_table_data.end());
     fake_header_code_and_maps_.insert(fake_header_code_and_maps_.begin(),
                                       fake_mapping_data.begin(), fake_mapping_data.end());
+    fake_header_code_and_maps_.insert(fake_header_code_and_maps_.begin(),
+                                      fake_gc_map_.begin(), fake_gc_map_.end());
     fake_header_code_and_maps_.insert(fake_header_code_and_maps_.end(),
                                       fake_code_.begin(), fake_code_.end());
 
@@ -95,12 +98,10 @@
     method_f_ = my_klass_->FindVirtualMethod("f", "()I");
     ASSERT_TRUE(method_f_ != NULL);
     method_f_->SetEntryPointFromQuickCompiledCode(code_ptr);
-    method_f_->SetNativeGcMap(&fake_gc_map_[0]);
 
     method_g_ = my_klass_->FindVirtualMethod("g", "(I)V");
     ASSERT_TRUE(method_g_ != NULL);
     method_g_->SetEntryPointFromQuickCompiledCode(code_ptr);
-    method_g_->SetNativeGcMap(&fake_gc_map_[0]);
   }
 
   const DexFile* dex_;
diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h
index 8844f1c..e70a48e 100644
--- a/runtime/mirror/art_method-inl.h
+++ b/runtime/mirror/art_method-inl.h
@@ -290,14 +290,23 @@
   return reinterpret_cast<const uint8_t*>(code_pointer) - offset;
 }
 
-inline void ArtMethod::SetOatNativeGcMapOffset(uint32_t gc_map_offset) {
-  DCHECK(!Runtime::Current()->IsStarted());
-  SetNativeGcMap(reinterpret_cast<uint8_t*>(gc_map_offset));
+inline const uint8_t* ArtMethod::GetNativeGcMap(size_t pointer_size) {
+  const void* code_pointer = GetQuickOatCodePointer(pointer_size);
+  if (code_pointer == nullptr) {
+    return nullptr;
+  }
+  return GetNativeGcMap(code_pointer, pointer_size);
 }
 
-inline uint32_t ArtMethod::GetOatNativeGcMapOffset() {
-  DCHECK(!Runtime::Current()->IsStarted());
-  return PointerToLowMemUInt32(GetNativeGcMap());
+inline const uint8_t* ArtMethod::GetNativeGcMap(const void* code_pointer, size_t pointer_size) {
+  DCHECK(code_pointer != nullptr);
+  DCHECK_EQ(code_pointer, GetQuickOatCodePointer(pointer_size));
+  uint32_t offset =
+      reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].gc_map_offset_;
+  if (UNLIKELY(offset == 0u)) {
+    return nullptr;
+  }
+  return reinterpret_cast<const uint8_t*>(code_pointer) - offset;
 }
 
 inline bool ArtMethod::IsRuntimeMethod() {
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index 0c07448..1fa42c6 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -384,29 +384,15 @@
   const uint8_t* GetVmapTable(const void* code_pointer, size_t pointer_size)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  const uint8_t* GetNativeGcMap() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    CheckObjectSizeEqualsMirrorSize();
-    return GetNativeGcMapPtrSize(sizeof(void*));
-  }
-  ALWAYS_INLINE const uint8_t* GetNativeGcMapPtrSize(size_t pointer_size)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return GetFieldPtrWithSize<uint8_t*>(GcMapOffset(pointer_size), pointer_size);
-  }
-  template <VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  void SetNativeGcMap(const uint8_t* data) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    CheckObjectSizeEqualsMirrorSize();
-    SetNativeGcMapPtrSize(data, sizeof(void*));
-  }
-  template <VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  ALWAYS_INLINE void SetNativeGcMapPtrSize(const uint8_t* data, size_t pointer_size)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    SetFieldPtrWithSize<false, true, kVerifyFlags>(GcMapOffset(pointer_size), data,
-                                                   pointer_size);
-  }
+  // Callers should wrap the uint8_t* in a GcMap instance for convenient access.
+  const uint8_t* GetNativeGcMap(size_t pointer_size)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const uint8_t* GetNativeGcMap(const void* code_pointer, size_t pointer_size)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // When building the oat need a convenient place to stuff the offset of the native GC map.
-  void SetOatNativeGcMapOffset(uint32_t gc_map_offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  uint32_t GetOatNativeGcMapOffset() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  // void SetOatNativeGcMapOffset(uint32_t gc_map_offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  // uint32_t GetOatNativeGcMapOffset() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template <bool kCheckFrameSize = true>
   uint32_t GetFrameSizeInBytes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -455,11 +441,6 @@
         PtrSizedFields, entry_point_from_quick_compiled_code_) / sizeof(void*) * pointer_size);
   }
 
-  static MemberOffset GcMapOffset(size_t pointer_size) {
-    return MemberOffset(PtrSizedFieldsOffset() + OFFSETOF_MEMBER(
-        PtrSizedFields, gc_map_) / sizeof(void*) * pointer_size);
-  }
-
   void* GetEntryPointFromJni() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     CheckObjectSizeEqualsMirrorSize();
     return GetEntryPointFromJniPtrSize(sizeof(void*));
@@ -624,11 +605,6 @@
     // portable compiled code or the interpreter.
     void* entry_point_from_quick_compiled_code_;
 
-    // Pointer to a data structure created by the compiler and used by the garbage collector to
-    // determine which registers hold live references to objects within the heap. Keyed by native PC
-    // offsets for the quick compiler and dex PCs for the portable.
-    void* gc_map_;
-
     // Method dispatch from portable compiled code invokes this pointer which may cause bridging
     // into quick compiled code or the interpreter. Last to simplify entrypoint logic.
 #if defined(ART_USE_PORTABLE_COMPILER)
diff --git a/runtime/oat.cc b/runtime/oat.cc
index 4819396..a8fd250 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -23,7 +23,7 @@
 namespace art {
 
 const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
-const uint8_t OatHeader::kOatVersion[] = { '0', '4', '3', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '4', '4', '\0' };
 
 static size_t ComputeOatHeaderSize(const SafeMap<std::string, std::string>* variable_data) {
   size_t estimate = 0U;
@@ -491,35 +491,19 @@
   key_value_store_size_ = data_ptr - reinterpret_cast<char*>(&key_value_store_);
 }
 
-OatMethodOffsets::OatMethodOffsets()
-  : code_offset_(0),
-    gc_map_offset_(0)
-{}
-
-OatMethodOffsets::OatMethodOffsets(uint32_t code_offset,
-                                   uint32_t gc_map_offset
-                                   )
-  : code_offset_(code_offset),
-    gc_map_offset_(gc_map_offset)
-{}
+OatMethodOffsets::OatMethodOffsets(uint32_t code_offset) : code_offset_(code_offset) {
+}
 
 OatMethodOffsets::~OatMethodOffsets() {}
 
-OatQuickMethodHeader::OatQuickMethodHeader()
-  : mapping_table_offset_(0),
-    vmap_table_offset_(0),
-    frame_info_(0, 0, 0),
-    code_size_(0)
-{}
-
 OatQuickMethodHeader::OatQuickMethodHeader(
-    uint32_t mapping_table_offset, uint32_t vmap_table_offset, uint32_t frame_size_in_bytes,
-    uint32_t core_spill_mask, uint32_t fp_spill_mask, uint32_t code_size)
-  : mapping_table_offset_(mapping_table_offset),
-    vmap_table_offset_(vmap_table_offset),
-    frame_info_(frame_size_in_bytes, core_spill_mask, fp_spill_mask),
-    code_size_(code_size)
-{}
+    uint32_t mapping_table_offset, uint32_t vmap_table_offset, uint32_t gc_map_offset,
+    uint32_t frame_size_in_bytes, uint32_t core_spill_mask, uint32_t fp_spill_mask,
+    uint32_t code_size)
+    : mapping_table_offset_(mapping_table_offset), vmap_table_offset_(vmap_table_offset),
+      gc_map_offset_(gc_map_offset),
+      frame_info_(frame_size_in_bytes, core_spill_mask, fp_spill_mask), code_size_(code_size) {
+}
 
 OatQuickMethodHeader::~OatQuickMethodHeader() {}
 
diff --git a/runtime/oat.h b/runtime/oat.h
index a5cb4bc..0534b1d 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -162,25 +162,20 @@
 
 class PACKED(4) OatMethodOffsets {
  public:
-  OatMethodOffsets();
-
-  OatMethodOffsets(uint32_t code_offset,
-                   uint32_t gc_map_offset);
+  OatMethodOffsets(uint32_t code_offset = 0);
 
   ~OatMethodOffsets();
 
   uint32_t code_offset_;
-  uint32_t gc_map_offset_;
 };
 
 // OatQuickMethodHeader precedes the raw code chunk generated by the Quick compiler.
 class PACKED(4) OatQuickMethodHeader {
  public:
-  OatQuickMethodHeader();
-
-  explicit OatQuickMethodHeader(uint32_t mapping_table_offset, uint32_t vmap_table_offset,
-                                uint32_t frame_size_in_bytes, uint32_t core_spill_mask,
-                                uint32_t fp_spill_mask, uint32_t code_size);
+  OatQuickMethodHeader(uint32_t mapping_table_offset = 0U, uint32_t vmap_table_offset = 0U,
+                       uint32_t gc_map_offset = 0U, uint32_t frame_size_in_bytes = 0U,
+                       uint32_t core_spill_mask = 0U, uint32_t fp_spill_mask = 0U,
+                       uint32_t code_size = 0U);
 
   ~OatQuickMethodHeader();
 
@@ -188,6 +183,8 @@
   uint32_t mapping_table_offset_;
   // The offset in bytes from the start of the vmap table to the end of the header.
   uint32_t vmap_table_offset_;
+  // The offset in bytes from the start of the gc map to the end of the header.
+  uint32_t gc_map_offset_;
   // The stack frame information.
   QuickMethodFrameInfo frame_info_;
   // The code size in bytes.
diff --git a/runtime/oat_file-inl.h b/runtime/oat_file-inl.h
index 9570bb5..a0cec03 100644
--- a/runtime/oat_file-inl.h
+++ b/runtime/oat_file-inl.h
@@ -78,6 +78,31 @@
   return reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].frame_info_.FpSpillMask();
 }
 
+const uint8_t* OatFile::OatMethod::GetGcMap() const {
+  const void* code = mirror::ArtMethod::EntryPointToCodePointer(GetQuickCode());
+  if (code == nullptr) {
+    return nullptr;
+  }
+  uint32_t offset = reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].gc_map_offset_;
+  if (UNLIKELY(offset == 0u)) {
+    return nullptr;
+  }
+  return reinterpret_cast<const uint8_t*>(code) - offset;
+}
+
+uint32_t OatFile::OatMethod::GetGcMapOffset() const {
+  const uint8_t* gc_map = GetGcMap();
+  return static_cast<uint32_t>(gc_map != nullptr ? gc_map - begin_ : 0u);
+}
+
+uint32_t OatFile::OatMethod::GetGcMapOffsetOffset() const {
+  const OatQuickMethodHeader* method_header = GetOatQuickMethodHeader();
+  if (method_header == nullptr) {
+    return 0u;
+  }
+  return reinterpret_cast<const byte*>(&method_header->gc_map_offset_) - begin_;
+}
+
 inline uint32_t OatFile::OatMethod::GetMappingTableOffset() const {
   const uint8_t* mapping_table = GetMappingTable();
   return static_cast<uint32_t>(mapping_table != nullptr ? mapping_table - begin_ : 0u);
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 9ba860c..9c06ebe 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -572,27 +572,22 @@
 const OatFile::OatMethod OatFile::OatClass::GetOatMethod(uint32_t method_index) const {
   const OatMethodOffsets* oat_method_offsets = GetOatMethodOffsets(method_index);
   if (oat_method_offsets == nullptr) {
-    return OatMethod(nullptr, 0, 0);
+    return OatMethod(nullptr, 0);
   }
   if (oat_file_->IsExecutable() ||
       Runtime::Current() == nullptr ||        // This case applies for oatdump.
       Runtime::Current()->IsCompiler()) {
-    return OatMethod(
-        oat_file_->Begin(),
-        oat_method_offsets->code_offset_,
-        oat_method_offsets->gc_map_offset_);
+    return OatMethod(oat_file_->Begin(), oat_method_offsets->code_offset_);
   } else {
     // We aren't allowed to use the compiled code. We just force it down the interpreted version.
-    return OatMethod(oat_file_->Begin(), 0, 0);
+    return OatMethod(oat_file_->Begin(), 0);
   }
 }
 
 OatFile::OatMethod::OatMethod(const byte* base,
-                              const uint32_t code_offset,
-                              const uint32_t gc_map_offset)
+                              const uint32_t code_offset)
   : begin_(base),
-    code_offset_(code_offset),
-    native_gc_map_offset_(gc_map_offset) {
+    code_offset_(code_offset) {
 }
 
 OatFile::OatMethod::~OatMethod() {}
@@ -603,7 +598,6 @@
   method->SetEntryPointFromPortableCompiledCode(GetPortableCode());
 #endif
   method->SetEntryPointFromQuickCompiledCode(GetQuickCode());
-  method->SetNativeGcMap(GetNativeGcMap());
 }
 
 bool OatFile::IsPic() const {
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 488988e..5d92a05 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -96,9 +96,6 @@
     uint32_t GetCodeOffset() const {
       return code_offset_;
     }
-    uint32_t GetNativeGcMapOffset() const {
-      return native_gc_map_offset_;
-    }
 
     const void* GetPortableCode() const {
       // TODO: encode whether code is portable/quick in flags within OatMethod.
@@ -134,10 +131,6 @@
     const OatQuickMethodHeader* GetOatQuickMethodHeader() const;
     uint32_t GetOatQuickMethodHeaderOffset() const;
 
-    const uint8_t* GetNativeGcMap() const {
-      return GetOatPointer<const uint8_t*>(native_gc_map_offset_);
-    }
-
     size_t GetFrameSizeInBytes() const;
     uint32_t GetCoreSpillMask() const;
     uint32_t GetFpSpillMask() const;
@@ -150,12 +143,14 @@
     uint32_t GetVmapTableOffset() const;
     uint32_t GetVmapTableOffsetOffset() const;
 
+    const uint8_t* GetGcMap() const;
+    uint32_t GetGcMapOffset() const;
+    uint32_t GetGcMapOffsetOffset() const;
+
     ~OatMethod();
 
     // Create an OatMethod with offsets relative to the given base address
-    OatMethod(const byte* base,
-              const uint32_t code_offset,
-              const uint32_t gc_map_offset);
+    OatMethod(const byte* base, const uint32_t code_offset);
 
     OatMethod() {}
 
@@ -171,7 +166,6 @@
     const byte* begin_;
 
     uint32_t code_offset_;
-    uint32_t native_gc_map_offset_;
 
     friend class OatClass;
   };
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 74119bb..a3eb9fb 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -2074,7 +2074,7 @@
     } else {
       // Java method.
       // Portable path use DexGcMap and store in Method.native_gc_map_.
-      const uint8_t* gc_map = m->GetNativeGcMap();
+      const uint8_t* gc_map = m->GetNativeGcMap(sizeof(void*));
       CHECK(gc_map != nullptr) << PrettyMethod(m);
       verifier::DexPcToReferenceMap dex_gc_map(gc_map);
       uint32_t dex_pc = shadow_frame->GetDexPC();
@@ -2108,7 +2108,7 @@
 
     // Process register map (which native and runtime methods don't have)
     if (!m->IsNative() && !m->IsRuntimeMethod() && !m->IsProxyMethod()) {
-      const uint8_t* native_gc_map = m->GetNativeGcMap();
+      const uint8_t* native_gc_map = m->GetNativeGcMap(sizeof(void*));
       CHECK(native_gc_map != nullptr) << PrettyMethod(m);
       const DexFile::CodeItem* code_item = m->GetCodeItem();
       DCHECK(code_item != nullptr) << PrettyMethod(m);  // Can't be nullptr or how would we compile its instructions?
diff --git a/test/004-ReferenceMap/stack_walk_refmap_jni.cc b/test/004-ReferenceMap/stack_walk_refmap_jni.cc
index 7929554..1bd3843 100644
--- a/test/004-ReferenceMap/stack_walk_refmap_jni.cc
+++ b/test/004-ReferenceMap/stack_walk_refmap_jni.cc
@@ -57,7 +57,7 @@
     }
     LOG(INFO) << "At " << PrettyMethod(m, false);
 
-    NativePcOffsetToReferenceMap map(m->GetNativeGcMap());
+    NativePcOffsetToReferenceMap map(m->GetNativeGcMap(sizeof(void*)));
 
     if (m->IsCalleeSaveMethod()) {
       LOG(WARNING) << "no PC for " << PrettyMethod(m);
diff --git a/test/004-StackWalk/stack_walk_jni.cc b/test/004-StackWalk/stack_walk_jni.cc
index 30a0d59..2d55cc8 100644
--- a/test/004-StackWalk/stack_walk_jni.cc
+++ b/test/004-StackWalk/stack_walk_jni.cc
@@ -59,7 +59,7 @@
     }
     const uint8_t* reg_bitmap = NULL;
     if (!IsShadowFrame()) {
-      NativePcOffsetToReferenceMap map(m->GetNativeGcMap());
+      NativePcOffsetToReferenceMap map(m->GetNativeGcMap(sizeof(void*)));
       reg_bitmap = map.FindBitMap(GetNativePcOffset());
     }
     StringPiece m_name(m->GetName());