Add GC map to oat file

Change-Id: Ied0462c711a09e2542f231c3b2fa31239958bd28
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 5ff2293..20e6514 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1799,26 +1799,105 @@
 }
 
 void ClassLinker::VerifyClass(Class* klass) {
+  // TODO: assert that the monitor on the Class is held
   if (klass->IsVerified()) {
     return;
   }
 
-  CHECK_EQ(klass->GetStatus(), Class::kStatusResolved);
+  CHECK_EQ(klass->GetStatus(), Class::kStatusResolved) << PrettyClass(klass);
   klass->SetStatus(Class::kStatusVerifying);
 
-  if (verifier::DexVerifier::VerifyClass(klass)) {
+  // Try to use verification information from oat file, otherwise do runtime verification
+  const DexFile& dex_file = FindDexFile(klass->GetDexCache());
+  if (VerifyClassUsingOatFile(dex_file, klass) || verifier::DexVerifier::VerifyClass(klass)) {
+    // Make sure all classes referenced by catch blocks are resolved
+    ResolveClassExceptionHandlerTypes(dex_file, klass);
     klass->SetStatus(Class::kStatusVerified);
   } else {
     LOG(ERROR) << "Verification failed on class " << PrettyClass(klass);
     Thread* self = Thread::Current();
-    CHECK(!self->IsExceptionPending()) << PrettyTypeOf(self->GetException());
+    CHECK(!self->IsExceptionPending()) << PrettyTypeOf(self->GetException()) << PrettyClass(klass);
     self->ThrowNewExceptionF("Ljava/lang/VerifyError;", "Verification of %s failed",
         PrettyDescriptor(klass).c_str());
-    CHECK_EQ(klass->GetStatus(), Class::kStatusVerifying);
+    CHECK_EQ(klass->GetStatus(), Class::kStatusVerifying) << PrettyClass(klass);
     klass->SetStatus(Class::kStatusError);
   }
 }
 
+bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, Class* klass) {
+  if (!Runtime::Current()->IsStarted()) {
+    return false;
+  }
+  if (ClassLoader::UseCompileTimeClassPath()) {
+    return false;
+  }
+  const OatFile* oat_file = FindOatFileForDexFile(dex_file);
+  if (oat_file == NULL) {
+    return false;
+  }
+  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
+  CHECK(oat_dex_file != NULL) << PrettyClass(klass);
+  const char* descriptor = ClassHelper(klass).GetDescriptor();
+  uint32_t class_def_index;
+  bool found = dex_file.FindClassDefIndex(descriptor, class_def_index);
+  CHECK(found) << descriptor;
+  UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file->GetOatClass(class_def_index));
+  CHECK(oat_class.get() != NULL) << descriptor;
+  Class::Status status = oat_class->GetStatus();
+  if (status == Class::kStatusError) {
+    ThrowEarlierClassFailure(klass);
+    klass->SetVerifyErrorClass(Thread::Current()->GetException()->GetClass());
+    klass->SetStatus(Class::kStatusError);
+    return true;
+  }
+  if (status == Class::kStatusVerified || status == Class::kStatusInitialized) {
+    return true;
+  }
+  if (status == Class::kStatusNotReady) {
+    return false;
+  }
+  LOG(FATAL) << "Unexpected class status: " << status;
+  return false;
+}
+
+void ClassLinker::ResolveClassExceptionHandlerTypes(const DexFile& dex_file, Class* klass) {
+  for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
+    ResolveMethodExceptionHandlerTypes(dex_file, klass->GetDirectMethod(i));
+  }
+  for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
+    ResolveMethodExceptionHandlerTypes(dex_file, klass->GetVirtualMethod(i));
+  }
+}
+
+void ClassLinker::ResolveMethodExceptionHandlerTypes(const DexFile& dex_file, Method* method) {
+  // similar to DexVerifier::ScanTryCatchBlocks and dex2oat's ResolveExceptionsForMethod.
+  const DexFile::CodeItem* code_item = dex_file.GetCodeItem(method->GetCodeItemOffset());
+  if (code_item == NULL) {
+    return;  // native or abstract method
+  }
+  if (code_item->tries_size_ == 0) {
+    return;  // nothing to process
+  }
+  const byte* handlers_ptr = DexFile::GetCatchHandlerData(*code_item, 0);
+  uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
+  ClassLinker* linker = Runtime::Current()->GetClassLinker();
+  for (uint32_t idx = 0; idx < handlers_size; idx++) {
+    CatchHandlerIterator iterator(handlers_ptr);
+    for (; iterator.HasNext(); iterator.Next()) {
+      // Ensure exception types are resolved so that they don't need resolution to be delivered,
+      // unresolved exception types will be ignored by exception delivery
+      if (iterator.GetHandlerTypeIndex() != DexFile::kDexNoIndex16) {
+        Class* exception_type = linker->ResolveType(iterator.GetHandlerTypeIndex(), method);
+        if (exception_type == NULL) {
+          DCHECK(Thread::Current()->IsExceptionPending());
+          Thread::Current()->ClearException();
+        }
+      }
+    }
+    handlers_ptr = iterator.EndDataPointer();
+  }
+}
+
 static void CheckProxyConstructor(Method* constructor);
 static void CheckProxyMethod(Method* method, SirtRef<Method>& prototype);
 
@@ -2025,7 +2104,7 @@
       return false;
     }
 
-    DCHECK_EQ(klass->GetStatus(), Class::kStatusVerified);
+    DCHECK_EQ(klass->GetStatus(), Class::kStatusVerified) << PrettyClass(klass);
 
     klass->SetClinitThreadId(self->GetTid());
     klass->SetStatus(Class::kStatusInitializing);
@@ -2211,7 +2290,7 @@
       if (!super_initialized) {
         if (!can_run_clinit) {
          // Don't set status to error when we can't run <clinit>.
-         CHECK_EQ(klass->GetStatus(), Class::kStatusInitializing);
+         CHECK_EQ(klass->GetStatus(), Class::kStatusInitializing) << PrettyClass(klass);
          klass->SetStatus(Class::kStatusVerified);
          return false;
         }
diff --git a/src/class_linker.h b/src/class_linker.h
index 45b1aa2..fde4d5f 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -266,6 +266,9 @@
   ObjectArray<StackTraceElement>* AllocStackTraceElementArray(size_t length);
 
   void VerifyClass(Class* klass);
+  bool VerifyClassUsingOatFile(const DexFile& dex_file, Class* klass);
+  void ResolveClassExceptionHandlerTypes(const DexFile& dex_file, Class* klass);
+  void ResolveMethodExceptionHandlerTypes(const DexFile& dex_file, Method* klass);
 
   Class* CreateProxyClass(String* name, ObjectArray<Class>* interfaces, ClassLoader* loader,
                           ObjectArray<Method>* methods, ObjectArray<ObjectArray<Class> >* throws);
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 8b0e1a1..f680d2b 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -439,7 +439,6 @@
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_methods_),           "dexCacheResolvedMethods"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_types_),             "dexCacheResolvedTypes"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_strings_),                    "dexCacheStrings"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, gc_map_),                               "gcMap"));
 
     // alphabetical 32-bit
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, access_flags_),        "accessFlags"));
@@ -448,6 +447,7 @@
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, core_spill_mask_),     "coreSpillMask"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, fp_spill_mask_),       "fpSpillMask"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, frame_size_in_bytes_), "frameSizeInBytes"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, gc_map_),              "gcMap"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, invoke_stub_),         "invokeStub"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, mapping_table_),       "mappingTable"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, method_dex_index_),    "methodDexIndex"));
diff --git a/src/common_test.h b/src/common_test.h
index c89527c..402766f 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -105,6 +105,7 @@
                                      const uint32_t fp_spill_mask,
                                      const uint32_t* mapping_table,
                                      const uint16_t* vmap_table,
+                                     const uint8_t* gc_map,
                                      const Method::InvokeStub* invoke_stub) {
       return OatFile::OatMethod(NULL,
                                 reinterpret_cast<uint32_t>(code),
@@ -113,6 +114,7 @@
                                 fp_spill_mask,
                                 reinterpret_cast<uint32_t>(mapping_table),
                                 reinterpret_cast<uint32_t>(vmap_table),
+                                reinterpret_cast<uint32_t>(gc_map),
                                 reinterpret_cast<uint32_t>(invoke_stub));
   }
 
@@ -148,6 +150,7 @@
                                                       compiled_method->GetFpSpillMask(),
                                                       &compiled_method->GetMappingTable()[0],
                                                       &compiled_method->GetVmapTable()[0],
+                                                      NULL,
                                                       method_invoke_stub);
       oat_method.LinkMethodPointers(method);
     } else {
@@ -160,6 +163,7 @@
                                                       0,
                                                       NULL,
                                                       NULL,
+                                                      NULL,
                                                       method_invoke_stub);
       oat_method.LinkMethodPointers(method);
     }
diff --git a/src/compiled_method.cc b/src/compiled_method.cc
index 67bdd9a..40230b4 100644
--- a/src/compiled_method.cc
+++ b/src/compiled_method.cc
@@ -5,16 +5,17 @@
 namespace art {
 
 CompiledMethod::CompiledMethod(InstructionSet instruction_set,
-                               std::vector<short>& short_code,
+                               const std::vector<uint16_t>& short_code,
                                const size_t frame_size_in_bytes,
                                const uint32_t core_spill_mask,
                                const uint32_t fp_spill_mask,
-                               std::vector<uint32_t>& mapping_table,
-                               std::vector<uint16_t>& vmap_table)
+                               const std::vector<uint32_t>& mapping_table,
+                               const std::vector<uint16_t>& vmap_table)
     : instruction_set_(instruction_set), frame_size_in_bytes_(frame_size_in_bytes),
       core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask) {
   CHECK_NE(short_code.size(), 0U);
   CHECK_GE(vmap_table.size(), 1U);  // should always contain an entry for LR
+  CHECK_LE(vmap_table.size(), (1U << 16) - 1); // length must fit in 2^16-1
 
   size_t code_byte_count = short_code.size() * sizeof(short_code[0]);
   std::vector<uint8_t> byte_code(code_byte_count);
@@ -42,8 +43,33 @@
   DCHECK_EQ(vmap_table_[0], static_cast<uint32_t>(__builtin_popcount(core_spill_mask) + __builtin_popcount(fp_spill_mask)));
 }
 
+void CompiledMethod::SetGcMap(const std::vector<uint8_t>& gc_map) {
+  CHECK_NE(gc_map.size(), 0U);
+
+  // Should only be used with CompiledMethods created with oatCompileMethod
+  CHECK_NE(mapping_table_.size(), 0U);
+  CHECK_NE(vmap_table_.size(), 0U);
+
+  std::vector<uint8_t> length_prefixed_gc_map;
+  length_prefixed_gc_map.push_back((gc_map.size() & 0xff000000) >> 24);
+  length_prefixed_gc_map.push_back((gc_map.size() & 0x00ff0000) >> 16);
+  length_prefixed_gc_map.push_back((gc_map.size() & 0x0000ff00) >> 8);
+  length_prefixed_gc_map.push_back((gc_map.size() & 0x000000ff) >> 0);
+  length_prefixed_gc_map.insert(length_prefixed_gc_map.end(),
+                                gc_map.begin(),
+                                gc_map.end());
+  DCHECK_EQ(gc_map.size() + 4, length_prefixed_gc_map.size());
+  DCHECK_EQ(gc_map.size(),
+            static_cast<size_t>((length_prefixed_gc_map[0] << 24) |
+                                (length_prefixed_gc_map[1] << 16) |
+                                (length_prefixed_gc_map[2] << 8) |
+                                (length_prefixed_gc_map[3] << 0)));
+
+  gc_map_ = length_prefixed_gc_map;
+}
+
 CompiledMethod::CompiledMethod(InstructionSet instruction_set,
-                               std::vector<uint8_t>& code,
+                               const std::vector<uint8_t>& code,
                                const size_t frame_size_in_bytes,
                                const uint32_t core_spill_mask,
                                const uint32_t fp_spill_mask)
@@ -82,6 +108,10 @@
   return vmap_table_;
 }
 
+const std::vector<uint8_t>& CompiledMethod::GetGcMap() const {
+  return gc_map_;
+}
+
 uint32_t CompiledMethod::AlignCode(uint32_t offset) const {
   return AlignCode(offset, instruction_set_);
 }
diff --git a/src/compiled_method.h b/src/compiled_method.h
index 4b5a78b..4528e52 100644
--- a/src/compiled_method.h
+++ b/src/compiled_method.h
@@ -14,16 +14,19 @@
  public:
   // Create a CompiledMethod from the oatCompileMethod
   CompiledMethod(InstructionSet instruction_set,
-                 std::vector<short>& code,
+                 const std::vector<uint16_t>& code,
                  const size_t frame_size_in_bytes,
                  const uint32_t core_spill_mask,
                  const uint32_t fp_spill_mask,
-                 std::vector<uint32_t>& mapping_table,
-                 std::vector<uint16_t>& vmap_table);
+                 const std::vector<uint32_t>& mapping_table,
+                 const std::vector<uint16_t>& vmap_table);
+
+  // Add a GC map to a CompiledMethod created by oatCompileMethod
+  void SetGcMap(const std::vector<uint8_t>& gc_map);
 
   // Create a CompiledMethod from the JniCompiler
   CompiledMethod(InstructionSet instruction_set,
-                 std::vector<uint8_t>& code,
+                 const std::vector<uint8_t>& code,
                  const size_t frame_size_in_bytes,
                  const uint32_t core_spill_mask,
                  const uint32_t fp_spill_mask);
@@ -37,6 +40,8 @@
   uint32_t GetFpSpillMask() const;
   const std::vector<uint32_t>& GetMappingTable() const;
   const std::vector<uint16_t>& GetVmapTable() const;
+  const std::vector<uint8_t>& GetGcMap() const;
+
   // Aligns an offset from a page aligned value to make it suitable
   // for code storage. important to ensure that PC relative value
   // computations work out as expected on ARM.
@@ -61,6 +66,7 @@
   const uint32_t fp_spill_mask_;
   std::vector<uint32_t> mapping_table_;
   std::vector<uint16_t> vmap_table_;
+  std::vector<uint8_t> gc_map_;
 };
 
 class CompiledInvokeStub {
diff --git a/src/compiler.cc b/src/compiler.cc
index 88e156d..d700adb 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -8,6 +8,7 @@
 #include "class_linker.h"
 #include "class_loader.h"
 #include "dex_cache.h"
+#include "dex_verifier.h"
 #include "jni_compiler.h"
 #include "jni_internal.h"
 #include "oat_file.h"
@@ -136,6 +137,7 @@
 
 void Compiler::PostCompile(const ClassLoader* class_loader,
                            const std::vector<const DexFile*>& dex_files) {
+  SetGcMaps(class_loader, dex_files);
   SetCodeAndDirectMethods(dex_files);
 }
 
@@ -481,6 +483,70 @@
   return it->second;
 }
 
+void Compiler::SetGcMaps(const ClassLoader* class_loader, const std::vector<const DexFile*>& dex_files) {
+  for (size_t i = 0; i != dex_files.size(); ++i) {
+    const DexFile* dex_file = dex_files[i];
+    CHECK(dex_file != NULL);
+    SetGcMapsDexFile(class_loader, *dex_file);
+  }
+}
+
+void Compiler::SetGcMapsDexFile(const ClassLoader* class_loader, const DexFile& dex_file) {
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  DexCache* dex_cache = class_linker->FindDexCache(dex_file);
+  for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs(); class_def_index++) {
+    const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
+    const char* descriptor = dex_file.GetClassDescriptor(class_def);
+    Class* klass = class_linker->FindClass(descriptor, class_loader);
+    if (klass == NULL || !klass->IsVerified()) {
+      Thread::Current()->ClearException();
+      continue;
+    }
+    const byte* class_data = dex_file.GetClassData(class_def);
+    if (class_data == NULL) {
+      // empty class such as a marker interface
+      continue;
+    }
+    ClassDataItemIterator it(dex_file, class_data);
+    while (it.HasNextStaticField()) {
+      it.Next();
+    }
+    while (it.HasNextInstanceField()) {
+      it.Next();
+    }
+    while (it.HasNextDirectMethod()) {
+      Method* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(), dex_cache,
+                                                   class_loader, true);
+      SetGcMapsMethod(dex_file, method);
+      it.Next();
+    }
+    while (it.HasNextVirtualMethod()) {
+      Method* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(), dex_cache,
+                                                   class_loader, false);
+      SetGcMapsMethod(dex_file, method);
+      it.Next();
+    }
+  }
+}
+
+void Compiler::SetGcMapsMethod(const DexFile& dex_file, Method* method) {
+  if (method == NULL) {
+    Thread::Current()->ClearException();
+    return;
+  }
+  uint16_t method_idx = method->GetDexMethodIndex();
+  MethodReference ref(&dex_file, method_idx);
+  CompiledMethod* compiled_method = GetCompiledMethod(ref);
+  if (compiled_method == NULL) {
+    return;
+  }
+  const std::vector<uint8_t>* gc_map = verifier::DexVerifier::GetGcMap(ref);
+  if (gc_map == NULL) {
+    return;
+  }
+  compiled_method->SetGcMap(*gc_map);
+}
+
 void Compiler::SetCodeAndDirectMethods(const std::vector<const DexFile*>& dex_files) {
   for (size_t i = 0; i != dex_files.size(); ++i) {
     const DexFile* dex_file = dex_files[i];
diff --git a/src/compiler.h b/src/compiler.h
index f59587f..bf21ed6 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -58,10 +58,36 @@
 
   // A class is uniquely located by its DexFile and the class_defs_ table index into that DexFile
   typedef std::pair<const DexFile*, uint32_t> ClassReference;
+  struct ClassReferenceHash {
+    size_t operator()(const ClassReference& id) const {
+      size_t dex = reinterpret_cast<size_t>(id.first);
+      DCHECK_NE(dex, static_cast<size_t>(0));
+      dex += 33;  // dex is an aligned pointer, get some non-zero low bits
+      size_t idx = id.second;
+      if (idx == 0) {  // special case of a method index of 0
+        return dex * 5381;
+      } else {
+        return dex * idx;
+      }
+    }
+  };
   CompiledClass* GetCompiledClass(ClassReference ref) const;
 
   // A method is uniquely located by its DexFile and the method_ids_ table index into that DexFile
   typedef std::pair<const DexFile*, uint32_t> MethodReference;
+  struct MethodReferenceHash {
+    size_t operator()(const MethodReference& id) const {
+      size_t dex = reinterpret_cast<size_t>(id.first);
+      DCHECK_NE(dex, static_cast<size_t>(0));
+      dex += 33;  // dex is an aligned pointer, get some non-zero low bits
+      size_t idx = id.second;
+      if (idx == 0) {  // special case of a method index of 0
+        return dex * 5381;
+      } else {
+        return dex * idx;
+      }
+    }
+  };
   CompiledMethod* GetCompiledMethod(MethodReference ref) const;
 
   const CompiledInvokeStub* FindInvokeStub(bool is_static, const char* shorty) const;
@@ -116,6 +142,10 @@
   void CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, uint32_t method_idx,
                      const ClassLoader* class_loader, const DexFile& dex_file);
 
+  void SetGcMaps(const ClassLoader* class_loader, const std::vector<const DexFile*>& dex_files);
+  void SetGcMapsDexFile(const ClassLoader* class_loader, const DexFile& dex_file);
+  void SetGcMapsMethod(const DexFile& dex_file, Method* method);
+
   // After compiling, walk all the DexCaches and set the code and
   // method pointers of CodeAndDirectMethods entries in the DexCaches.
   void SetCodeAndDirectMethods(const std::vector<const DexFile*>& dex_files);
@@ -127,36 +157,10 @@
   InstructionSet instruction_set_;
   JniCompiler jni_compiler_;
 
-  struct ClassReferenceHash {
-    size_t operator()(const ClassReference& id) const {
-      size_t dex = reinterpret_cast<size_t>(id.first);
-      DCHECK_NE(dex, static_cast<size_t>(0));
-      dex += 33;  // dex is an aligned pointer, get some non-zero low bits
-      size_t idx = id.second;
-      if (idx == 0) {  // special case of a method index of 0
-        return dex * 5381;
-      } else {
-        return dex * idx;
-      }
-    }
-  };
   typedef std::tr1::unordered_map<const ClassReference, CompiledClass*, ClassReferenceHash> ClassTable;
   // All class references that this compiler has compiled
   ClassTable compiled_classes_;
 
-  struct MethodReferenceHash {
-    size_t operator()(const MethodReference& id) const {
-      size_t dex = reinterpret_cast<size_t>(id.first);
-      DCHECK_NE(dex, static_cast<size_t>(0));
-      dex += 33;  // dex is an aligned pointer, get some non-zero low bits
-      size_t idx = id.second;
-      if (idx == 0) {  // special case of a method index of 0
-        return dex * 5381;
-      } else {
-        return dex * idx;
-      }
-    }
-  };
   typedef std::tr1::unordered_map<const MethodReference, CompiledMethod*, MethodReferenceHash> MethodTable;
   // All method references that this compiler has compiled
   MethodTable compiled_methods_;
diff --git a/src/compiler/CompilerIR.h b/src/compiler/CompilerIR.h
index 49c84c1..2e89ab5 100644
--- a/src/compiler/CompilerIR.h
+++ b/src/compiler/CompilerIR.h
@@ -215,7 +215,7 @@
     int totalSize;                      // header + code size
     AssemblerStatus assemblerStatus;    // Success or fix and retry
     int assemblerRetries;
-    std::vector<short> codeBuffer;
+    std::vector<uint16_t> codeBuffer;
     std::vector<uint32_t> mappingTable;
     std::vector<uint16_t> coreVmapTable;
     std::vector<uint16_t> fpVmapTable;
diff --git a/src/compiler/codegen/arm/Assemble.cc b/src/compiler/codegen/arm/Assemble.cc
index 9a1a30e..a73a27a 100644
--- a/src/compiler/codegen/arm/Assemble.cc
+++ b/src/compiler/codegen/arm/Assemble.cc
@@ -974,12 +974,12 @@
  */
 #define PADDING_MOV_R5_R5               0x1C2D
 
-STATIC void pushWord(std::vector<short>&buf, int data) {
+STATIC void pushWord(std::vector<uint16_t>&buf, int data) {
     buf.push_back( data & 0xffff);
     buf.push_back( (data >> 16) & 0xffff);
 }
 
-void alignBuffer(std::vector<short>&buf, size_t offset) {
+void alignBuffer(std::vector<uint16_t>&buf, size_t offset) {
     while (buf.size() < (offset/2))
         buf.push_back(0);
 }
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index 1172186..00b226d 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -5,6 +5,7 @@
 #include <iostream>
 
 #include "class_linker.h"
+#include "compiler.h"
 #include "dex_cache.h"
 #include "dex_file.h"
 #include "dex_instruction.h"
@@ -842,7 +843,7 @@
   return changed;
 }
 
-void RegisterLine::WriteReferenceBitMap(int8_t* data, size_t max_bytes) {
+void RegisterLine::WriteReferenceBitMap(std::vector<uint8_t>& data, size_t max_bytes) {
   for (size_t i = 0; i < num_regs_; i += 8) {
     uint8_t val = 0;
     for (size_t j = 0; j < 8 && (i + j) < num_regs_; j++) {
@@ -851,10 +852,12 @@
         val |= 1 << j;
       }
     }
-    if (val != 0) {
-      DCHECK_LT(i / 8, max_bytes);
-      data[i / 8] = val;
+    if ((i / 8) >= max_bytes) {
+      DCHECK_EQ(0, val);
+      continue;
     }
+    DCHECK_LT(i / 8, max_bytes) << "val=" << static_cast<uint32_t>(val);
+    data.push_back(val);
   }
 }
 
@@ -966,12 +969,18 @@
             << verifier.info_messages_.str() << Dumpable<DexVerifier>(verifier);
 }
 
-DexVerifier::DexVerifier(Method* method) : work_insn_idx_(-1), method_(method),
-                                           failure_(VERIFY_ERROR_NONE),
-
-                                           new_instance_count_(0), monitor_enter_count_(0) {
+DexVerifier::DexVerifier(Method* method)
+    : work_insn_idx_(-1),
+      method_(method),
+      failure_(VERIFY_ERROR_NONE),
+      new_instance_count_(0),
+      monitor_enter_count_(0) {
+  CHECK(method != NULL);
+  Runtime* runtime = Runtime::Current();
+  // We should only be running the verifier at compile time
+  CHECK(!runtime->IsStarted());
   const DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache();
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  ClassLinker* class_linker = runtime->GetClassLinker();
   dex_file_ = &class_linker->FindDexFile(dex_cache);
   code_item_ = dex_file_->GetCodeItem(method->GetCodeItemOffset());
 }
@@ -1063,7 +1072,7 @@
       insn_flags_[dex_pc].SetInTry();
     }
   }
-  /* Iterate over each of the handlers to verify target addresses. */
+  // Iterate over each of the handlers to verify target addresses.
   const byte* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0);
   uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
   ClassLinker* linker = Runtime::Current()->GetClassLinker();
@@ -1517,13 +1526,14 @@
   }
 
   /* Generate a register map and add it to the method. */
-  ByteArray* map = GenerateGcMap();
+  const std::vector<uint8_t>* map = GenerateGcMap();
   if (map == NULL) {
     return false;  // Not a real failure, but a failure to encode
   }
-  method_->SetGcMap(map);
+  Compiler::MethodReference ref(dex_file_, method_->GetDexMethodIndex());
+  verifier::DexVerifier::SetGcMap(ref, *map);
 #ifndef NDEBUG
-  VerifyGcMap();
+  VerifyGcMap(*map);
 #endif
   return true;
 }
@@ -3712,7 +3722,7 @@
   *log2_max_gc_pc = i;
 }
 
-ByteArray* DexVerifier::GenerateGcMap() {
+const std::vector<uint8_t>* DexVerifier::GenerateGcMap() {
   size_t num_entries, ref_bitmap_bits, pc_bits;
   ComputeGcMapSizes(&num_entries, &ref_bitmap_bits, &pc_bits);
   // There's a single byte to encode the size of each bitmap
@@ -3745,39 +3755,35 @@
     return NULL;
   }
   size_t table_size = ((pc_bytes + ref_bitmap_bytes) * num_entries ) + 4;
-  ByteArray* table = ByteArray::Alloc(table_size);
+  std::vector<uint8_t>* table = new std::vector<uint8_t>;
   if (table == NULL) {
     Fail(VERIFY_ERROR_GENERIC) << "Failed to encode GC map (size=" << table_size << ")";
     return NULL;
   }
   // Write table header
-  table->Set(0, format);
-  table->Set(1, ref_bitmap_bytes);
-  table->Set(2, num_entries & 0xFF);
-  table->Set(3, (num_entries >> 8) & 0xFF);
+  table->push_back(format);
+  table->push_back(ref_bitmap_bytes);
+  table->push_back(num_entries & 0xFF);
+  table->push_back((num_entries >> 8) & 0xFF);
   // Write table data
-  size_t offset = 4;
   for (size_t i = 0; i < code_item_->insns_size_in_code_units_; i++) {
     if (insn_flags_[i].IsGcPoint()) {
-      table->Set(offset, i & 0xFF);
-      offset++;
+      table->push_back(i & 0xFF);
       if (pc_bytes == 2) {
-        table->Set(offset, (i >> 8) & 0xFF);
-        offset++;
+        table->push_back((i >> 8) & 0xFF);
       }
       RegisterLine* line = reg_table_.GetLine(i);
-      line->WriteReferenceBitMap(table->GetData() + offset, ref_bitmap_bytes);
-      offset += ref_bitmap_bytes;
+      line->WriteReferenceBitMap(*table, ref_bitmap_bytes);
     }
   }
-  DCHECK(offset == table_size);
+  DCHECK_EQ(table->size(), table_size);
   return table;
 }
 
-void DexVerifier::VerifyGcMap() {
+void DexVerifier::VerifyGcMap(const std::vector<uint8_t>& data) {
   // Check that for every GC point there is a map entry, there aren't entries for non-GC points,
   // that the table data is well formed and all references are marked (or not) in the bitmap
-  PcToReferenceMap map(method_);
+  PcToReferenceMap map(&data[0], data.size());
   size_t map_index = 0;
   for(size_t i = 0; i < code_item_->insns_size_in_code_units_; i++) {
     const uint8_t* reg_bitmap = map.FindBitMap(i, false);
@@ -3834,5 +3840,26 @@
   return NULL;
 }
 
+DexVerifier::GcMapTable DexVerifier::gc_maps_;
+
+void DexVerifier::SetGcMap(Compiler::MethodReference ref, const std::vector<uint8_t>& gc_map) {
+  CHECK(GetGcMap(ref) == NULL);
+  gc_maps_[ref] = &gc_map;
+  CHECK(GetGcMap(ref) != NULL);
+}
+
+const std::vector<uint8_t>* DexVerifier::GetGcMap(Compiler::MethodReference ref) {
+  GcMapTable::const_iterator it = gc_maps_.find(ref);
+  if (it == gc_maps_.end()) {
+    return NULL;
+  }
+  CHECK(it->second != NULL);
+  return it->second;
+}
+
+void DexVerifier::DeleteGcMaps() {
+  STLDeleteValues(&gc_maps_);
+}
+
 }  // namespace verifier
 }  // namespace art
diff --git a/src/dex_verifier.h b/src/dex_verifier.h
index a0819e6..263dcae 100644
--- a/src/dex_verifier.h
+++ b/src/dex_verifier.h
@@ -4,11 +4,13 @@
 #define ART_SRC_DEX_VERIFY_H_
 
 #include "casts.h"
+#include "compiler.h"
 #include "dex_file.h"
 #include "dex_instruction.h"
 #include "macros.h"
 #include "object.h"
 #include "stl_util.h"
+#include "unordered_map.h"
 #include "UniquePtr.h"
 
 #include <deque>
@@ -17,6 +19,7 @@
 #include <vector>
 
 namespace art {
+
 namespace verifier {
 
 class DexVerifier;
@@ -702,7 +705,7 @@
   }
 
   // Write a bit at each register location that holds a reference
-  void WriteReferenceBitMap(int8_t* data, size_t max_bytes);
+  void WriteReferenceBitMap(std::vector<uint8_t>& data, size_t max_bytes);
  private:
 
   void CopyRegToLockDepth(size_t dst, size_t src) {
@@ -864,6 +867,9 @@
   // information
   void Dump(std::ostream& os);
 
+  static const std::vector<uint8_t>* GetGcMap(Compiler::MethodReference ref);
+  static void DeleteGcMaps();
+
  private:
 
   explicit DexVerifier(Method* method);
@@ -1173,10 +1179,10 @@
    * encode it in some clever fashion.
    * Returns a pointer to a newly-allocated RegisterMap, or NULL on failure.
    */
-  ByteArray* GenerateGcMap();
+  const std::vector<uint8_t>* GenerateGcMap();
 
   // Verify that the GC map associated with method_ is well formed
-  void VerifyGcMap();
+  void VerifyGcMap(const std::vector<uint8_t>& data);
 
   // Compute sizes for GC map data
   void ComputeGcMapSizes(size_t* gc_points, size_t* ref_bitmap_bits, size_t* log2_max_gc_pc);
@@ -1185,6 +1191,13 @@
     return insn_flags_[work_insn_idx_];
   }
 
+  typedef std::tr1::unordered_map<const Compiler::MethodReference,
+                                  const std::vector<uint8_t>*,
+                                  Compiler::MethodReferenceHash> GcMapTable;
+  // All the GC maps that the verifier has created
+  static GcMapTable gc_maps_;
+  static void SetGcMap(Compiler::MethodReference ref, const std::vector<uint8_t>& gc_map);
+
   RegTypeCache reg_types_;
 
   PcToRegisterLineTable reg_table_;
@@ -1220,11 +1233,11 @@
 // Lightweight wrapper for PC to reference bit maps.
 class PcToReferenceMap {
  public:
-  PcToReferenceMap(Method* m) {
-    data_ = down_cast<ByteArray*>(m->GetGcMap());
-    CHECK(data_ != NULL) << PrettyMethod(m);
+  PcToReferenceMap(const uint8_t* data, size_t data_length) {
+    data_ = data;
+    CHECK(data_ != NULL);
     // Check the size of the table agrees with the number of entries
-    size_t data_size = data_->GetLength() - 4;
+    size_t data_size = data_length - 4;
     DCHECK_EQ(EntryWidth() * NumEntries(), data_size);
   }
 
@@ -1288,9 +1301,9 @@
   }
 
   const uint8_t* GetData() const {
-    return reinterpret_cast<uint8_t*>(data_->GetData());
+    return data_;
   }
-  ByteArray* data_;  // The header and table data
+  const uint8_t* data_;  // The header and table data
 };
 
 }  // namespace verifier
diff --git a/src/image_writer.cc b/src/image_writer.cc
index f6d144e..861a878 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -398,6 +398,10 @@
     uint32_t vmap_table_offset = orig->GetOatVmapTableOffset();
     const byte* vmap_table = GetOatAddress(vmap_table_offset);
     copy->vmap_table_ = reinterpret_cast<const uint16_t*>(vmap_table);
+
+    uint32_t gc_map_offset = orig->GetOatGcMapOffset();
+    const byte* gc_map = GetOatAddress(gc_map_offset);
+    copy->gc_map_ = reinterpret_cast<const uint8_t*>(gc_map);
   }
 }
 
diff --git a/src/oat.cc b/src/oat.cc
index 0089410..c458ea3 100644
--- a/src/oat.cc
+++ b/src/oat.cc
@@ -72,6 +72,7 @@
     fp_spill_mask_(0),
     mapping_table_offset_(0),
     vmap_table_offset_(0),
+    gc_map_offset_(0),
     invoke_stub_offset_(0) {}
 
 OatMethodOffsets::OatMethodOffsets(uint32_t code_offset,
@@ -80,6 +81,7 @@
                                    uint32_t fp_spill_mask,
                                    uint32_t mapping_table_offset,
                                    uint32_t vmap_table_offset,
+                                   uint32_t gc_map_offset,
                                    uint32_t invoke_stub_offset)
   : code_offset_(code_offset),
     frame_size_in_bytes_(frame_size_in_bytes),
@@ -87,6 +89,7 @@
     fp_spill_mask_(fp_spill_mask),
     mapping_table_offset_(mapping_table_offset),
     vmap_table_offset_(vmap_table_offset),
+    gc_map_offset_(gc_map_offset),
     invoke_stub_offset_(invoke_stub_offset) {}
 
 OatMethodOffsets::~OatMethodOffsets() {}
diff --git a/src/oat.h b/src/oat.h
index 0ffc80f..4023aed 100644
--- a/src/oat.h
+++ b/src/oat.h
@@ -45,6 +45,7 @@
                    uint32_t fp_spill_mask,
                    uint32_t mapping_table_offset,
                    uint32_t vmap_table_offset,
+                   uint32_t gc_map_offset,
                    uint32_t invoke_stub_offset);
   ~OatMethodOffsets();
 
@@ -54,6 +55,7 @@
   uint32_t fp_spill_mask_;
   uint32_t mapping_table_offset_;
   uint32_t vmap_table_offset_;
+  uint32_t gc_map_offset_;
   uint32_t invoke_stub_offset_;
 };
 
diff --git a/src/oat_file.cc b/src/oat_file.cc
index a4bbc5f..6ffcb52 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -216,6 +216,7 @@
       oat_method_offsets.fp_spill_mask_,
       oat_method_offsets.mapping_table_offset_,
       oat_method_offsets.vmap_table_offset_,
+      oat_method_offsets.gc_map_offset_,
       oat_method_offsets.invoke_stub_offset_);
 }
 
@@ -226,6 +227,7 @@
                               const uint32_t fp_spill_mask,
                               const uint32_t mapping_table_offset,
                               const uint32_t vmap_table_offset,
+                              const uint32_t gc_map_offset,
                               const uint32_t invoke_stub_offset)
   : base_(base),
     code_offset_(code_offset),
@@ -234,6 +236,7 @@
     fp_spill_mask_(fp_spill_mask),
     mapping_table_offset_(mapping_table_offset),
     vmap_table_offset_(vmap_table_offset),
+    gc_map_offset_(gc_map_offset),
     invoke_stub_offset_(invoke_stub_offset) {
 
 #ifndef NDEBUG
@@ -260,6 +263,7 @@
   method->SetFpSpillMask(fp_spill_mask_);
   method->SetMappingTable(GetMappingTable());
   method->SetVmapTable(GetVmapTable());
+  method->SetGcMap(GetGcMap());
   method->SetInvokeStub(GetInvokeStub());
 }
 
@@ -271,6 +275,7 @@
   method->SetFpSpillMask(GetFpSpillMask());
   method->SetOatMappingTableOffset(GetMappingTableOffset());
   method->SetOatVmapTableOffset(GetVmapTableOffset());
+  method->SetOatGcMapOffset(GetGcMapOffset());
   method->SetOatInvokeStubOffset(GetInvokeStubOffset());
 }
 
diff --git a/src/oat_file.h b/src/oat_file.h
index 33a0e28..07e235b 100644
--- a/src/oat_file.h
+++ b/src/oat_file.h
@@ -61,6 +61,9 @@
     uint32_t GetVmapTableOffset() const {
       return vmap_table_offset_;
     }
+    uint32_t GetGcMapOffset() const {
+      return gc_map_offset_;
+    }
     uint32_t GetInvokeStubOffset() const {
       return invoke_stub_offset_;
     }
@@ -74,6 +77,9 @@
     const uint16_t* GetVmapTable() const {
       return GetOatPointer<const uint16_t*>(vmap_table_offset_);
     }
+    const uint8_t* GetGcMap() const {
+      return GetOatPointer<const uint8_t*>(gc_map_offset_);
+    }
     const Method::InvokeStub* GetInvokeStub() const {
       return GetOatPointer<const Method::InvokeStub*>(invoke_stub_offset_);
     }
@@ -88,6 +94,7 @@
               const uint32_t fp_spill_mask,
               const uint32_t mapping_table_offset,
               const uint32_t vmap_table_offset,
+              const uint32_t gc_map_offset,
               const uint32_t invoke_stub_offset);
 
    private:
@@ -107,6 +114,7 @@
     uint32_t fp_spill_mask_;
     uint32_t mapping_table_offset_;
     uint32_t vmap_table_offset_;
+    uint32_t gc_map_offset_;
     uint32_t invoke_stub_offset_;
 
     friend class OatClass;
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index 806ac71..9690142 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -193,6 +193,7 @@
   uint32_t fp_spill_mask = 0;
   uint32_t mapping_table_offset = 0;
   uint32_t vmap_table_offset = 0;
+  uint32_t gc_map_offset = 0;
   // derived from CompiledInvokeStub if available
   uint32_t invoke_stub_offset = 0;
 
@@ -258,6 +259,20 @@
       offset += vmap_table_size;
       oat_header_->UpdateChecksum(&vmap_table[0], vmap_table_size);
     }
+
+    const std::vector<uint8_t>& gc_map = compiled_method->GetGcMap();
+    size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]);
+    gc_map_offset = (gc_map_size == 0) ? 0 : offset;
+
+    // Deduplicate GC maps
+    std::map<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter = gc_map_offsets_.find(&gc_map);
+    if (gc_map_iter != gc_map_offsets_.end()) {
+      gc_map_offset = gc_map_iter->second;
+    } else {
+      gc_map_offsets_.insert(std::pair<const std::vector<uint8_t>*, uint32_t>(&gc_map, gc_map_offset));
+      offset += gc_map_size;
+      oat_header_->UpdateChecksum(&gc_map[0], gc_map_size);
+    }
   }
 
   const char* shorty = dex_file->GetMethodShorty(dex_file->GetMethodId(method_idx));
@@ -287,6 +302,7 @@
                          fp_spill_mask,
                          mapping_table_offset,
                          vmap_table_offset,
+                         gc_map_offset,
                          invoke_stub_offset);
 
   if (compiler_->IsImage()) {
@@ -301,6 +317,7 @@
     method->SetOatMappingTableOffset(mapping_table_offset);
     method->SetOatCodeOffset(code_offset);
     method->SetOatVmapTableOffset(vmap_table_offset);
+    method->SetOatGcMapOffset(gc_map_offset);
     method->SetOatInvokeStubOffset(invoke_stub_offset);
   }
   return offset;
@@ -567,6 +584,29 @@
       code_offset += vmap_table_size;
     }
     DCHECK_CODE_OFFSET();
+
+    const std::vector<uint8_t>& gc_map = compiled_method->GetGcMap();
+    size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]);
+
+    // Deduplicate GC maps
+    std::map<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter =
+        gc_map_offsets_.find(&gc_map);
+    if (gc_map_iter != gc_map_offsets_.end() &&
+        code_offset != method_offsets.gc_map_offset_) {
+      DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
+          || gc_map_iter->second == method_offsets.gc_map_offset_)
+          << PrettyMethod(method_idx, dex_file);
+    } else {
+      DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
+          || code_offset == method_offsets.gc_map_offset_)
+          << PrettyMethod(method_idx, dex_file);
+      if (!file->WriteFully(&gc_map[0], gc_map_size)) {
+        ReportWriteFailure("GC map", method_idx, dex_file, file);
+        return false;
+      }
+      code_offset += gc_map_size;
+    }
+    DCHECK_CODE_OFFSET();
   }
   const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
   const CompiledInvokeStub* compiled_invoke_stub = compiler_->FindInvokeStub(is_static, shorty);
diff --git a/src/oat_writer.h b/src/oat_writer.h
index 6ae0f4e..d1983a5 100644
--- a/src/oat_writer.h
+++ b/src/oat_writer.h
@@ -147,6 +147,7 @@
   std::map<const std::vector<uint8_t>*, uint32_t, MapCompare<std::vector<uint8_t> > > code_offsets_;
   std::map<const std::vector<uint16_t>*, uint32_t, MapCompare<std::vector<uint16_t> > > vmap_table_offsets_;
   std::map<const std::vector<uint32_t>*, uint32_t, MapCompare<std::vector<uint32_t> > > mapping_table_offsets_;
+  std::map<const std::vector<uint8_t>*, uint32_t, MapCompare<std::vector<uint8_t> > > gc_map_offsets_;
 
   DISALLOW_COPY_AND_ASSIGN(OatWriter);
 };
diff --git a/src/oatdump.cc b/src/oatdump.cc
index dd46896..91f4091 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -122,9 +122,10 @@
     for (size_t class_def_index = 0; class_def_index < dex_file->NumClassDefs(); class_def_index++) {
       const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
       const char* descriptor = dex_file->GetClassDescriptor(class_def);
-      os << StringPrintf("%d: %s (type_idx=%d)\n", class_def_index, descriptor, class_def.class_idx_);
       UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file.GetOatClass(class_def_index));
       CHECK(oat_class.get() != NULL);
+      os << StringPrintf("%d: %s (type_idx=%d) (", class_def_index, descriptor, class_def.class_idx_)
+         << oat_class->GetStatus() << ")\n";
       DumpOatClass(os, oat_file, *oat_class.get(), *dex_file, class_def);
     }
 
@@ -189,6 +190,8 @@
                        oat_method.GetMappingTable(), oat_method.GetMappingTableOffset());
     os << StringPrintf("\t\tvmap_table: %p (offset=%08x)\n",
                        oat_method.GetVmapTable(), oat_method.GetVmapTableOffset());
+    os << StringPrintf("\t\tgc_map: %p (offset=%08x)\n",
+                       oat_method.GetGcMap(), oat_method.GetGcMapOffset());
     os << StringPrintf("\t\tinvoke_stub: %p (offset=%08x)\n",
                        oat_method.GetInvokeStub(), oat_method.GetInvokeStubOffset());
   }
@@ -342,29 +345,36 @@
           StringAppendF(&summary, "\tNATIVE UNREGISTERED\n");
         }
         DCHECK(method->GetGcMap() == NULL) << PrettyMethod(method);
+        DCHECK_EQ(0U, method->GetGcMapLength()) << PrettyMethod(method);
         DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
       } else if (method->IsAbstract()) {
         StringAppendF(&summary, "\tABSTRACT\n");
         DCHECK(method->GetGcMap() == NULL) << PrettyMethod(method);
+        DCHECK_EQ(0U, method->GetGcMapLength()) << PrettyMethod(method);
         DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
       } else if (method->IsCalleeSaveMethod()) {
         StringAppendF(&summary, "\tCALLEE SAVE METHOD\n");
         DCHECK(method->GetGcMap() == NULL) << PrettyMethod(method);
+        DCHECK_EQ(0U, method->GetGcMapLength()) << PrettyMethod(method);
         DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
       } else {
-        if (method->GetGcMap() != NULL) {
-          size_t register_map_bytes = method->GetGcMap()->SizeOf();
-          state->stats_.register_map_bytes += register_map_bytes;
-        }
+        DCHECK(method->GetGcMap() != NULL) << PrettyMethod(method);
+        DCHECK_NE(0U, method->GetGcMapLength()) << PrettyMethod(method);
 
-        if (method->GetMappingTable() != NULL) {
-          size_t pc_mapping_table_bytes = method->GetMappingTableLength();
-          state->stats_.pc_mapping_table_bytes += pc_mapping_table_bytes;
-        }
+        size_t register_map_bytes = method->GetGcMapLength();
+        state->stats_.register_map_bytes += register_map_bytes;
+        StringAppendF(&summary, "GC=%d ", register_map_bytes);
+
+        size_t pc_mapping_table_bytes = method->GetMappingTableLength();
+        state->stats_.pc_mapping_table_bytes += pc_mapping_table_bytes;
+        StringAppendF(&summary, "Mapping=%d ", pc_mapping_table_bytes);
 
         const DexFile::CodeItem* code_item = MethodHelper(method).GetCodeItem();
         size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2;
         state->stats_.dex_instruction_bytes += dex_instruction_bytes;
+
+        StringAppendF(&summary, "\tSIZE Code=%d GC=%d Mapping=%d",
+                      dex_instruction_bytes, register_map_bytes, pc_mapping_table_bytes);
       }
     }
     state->os_ << summary << std::flush;
diff --git a/src/object.h b/src/object.h
index 5977977..7730974 100644
--- a/src/object.h
+++ b/src/object.h
@@ -701,12 +701,39 @@
     SetVmapTable(reinterpret_cast<uint16_t*>(vmap_table_offset));
   }
 
-  Object* GetGcMap() const {
-    return GetFieldObject<Object*>(OFFSET_OF_OBJECT_MEMBER(Method, gc_map_), false);
+  const uint8_t* GetGcMap() const {
+    const uint8_t* gc_map_raw = GetGcMapRaw();
+    if (gc_map_raw == NULL) {
+      return gc_map_raw;
+    }
+    return gc_map_raw + sizeof(uint32_t);
   }
 
-  void SetGcMap(Object* data) {
-    SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, gc_map_), data, false);
+  uint32_t GetGcMapLength() const {
+    const uint8_t* gc_map_raw = GetGcMapRaw();
+    if (gc_map_raw == NULL) {
+      return 0;
+    }
+    return static_cast<uint32_t>((gc_map_raw[0] << 24) |
+                                 (gc_map_raw[1] << 16) |
+                                 (gc_map_raw[2] << 8) |
+                                 (gc_map_raw[3] << 0));
+  }
+
+  const uint8_t* GetGcMapRaw() const {
+    return GetFieldPtr<uint8_t*>(OFFSET_OF_OBJECT_MEMBER(Method, gc_map_), false);
+  }
+  void SetGcMap(const uint8_t* data) {
+    SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(Method, gc_map_), data, false);
+  }
+
+  uint32_t GetOatGcMapOffset() const {
+    DCHECK(!Runtime::Current()->IsStarted());
+    return reinterpret_cast<uint32_t>(GetGcMapRaw());
+  }
+  void SetOatGcMapOffset(uint32_t gc_map_offset) {
+    DCHECK(!Runtime::Current()->IsStarted());
+    SetGcMap(reinterpret_cast<uint8_t*>(gc_map_offset));
   }
 
   size_t GetFrameSizeInBytes() const {
@@ -859,9 +886,6 @@
   // short cuts to declaring_class_->dex_cache_ member for fast compiled code access
   ObjectArray<String>* dex_cache_strings_;
 
-  // Garbage collection map
-  Object* gc_map_;
-
   // Access flags; low 16 bits are defined by spec.
   uint32_t access_flags_;
 
@@ -881,6 +905,9 @@
   // Total size in bytes of the frame
   size_t frame_size_in_bytes_;
 
+  // Garbage collection map
+  const uint8_t* gc_map_;
+
   // Native invocation stub entry point for calling from native to managed code.
   const InvokeStub* invoke_stub_;
 
diff --git a/src/thread.cc b/src/thread.cc
index a1df41b..6bee2c8 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -1495,7 +1495,9 @@
     }
     // Process register map (which native and callee save methods don't have)
     if (!m->IsNative() && !m->IsCalleeSaveMethod() && !m->IsProxyMethod()) {
-      verifier::PcToReferenceMap map(m);
+      CHECK(m->GetGcMap() != NULL) << PrettyMethod(m);
+      CHECK_NE(0U, m->GetGcMapLength()) << PrettyMethod(m);
+      verifier::PcToReferenceMap map(m->GetGcMap(), m->GetGcMapLength());
       const uint8_t* reg_bitmap = map.FindBitMap(m->ToDexPC(pc));
       CHECK(reg_bitmap != NULL);
       const VmapTable vmap_table(m->GetVmapTableRaw());
diff --git a/test/ReferenceMap/stack_walk_refmap_jni.cc b/test/ReferenceMap/stack_walk_refmap_jni.cc
index 547f8c9..a85e4ee 100644
--- a/test/ReferenceMap/stack_walk_refmap_jni.cc
+++ b/test/ReferenceMap/stack_walk_refmap_jni.cc
@@ -36,7 +36,7 @@
     }
     LOG(INFO) << "At " << PrettyMethod(m, false);
 
-    verifier::PcToReferenceMap map(m);
+    verifier::PcToReferenceMap map(m->GetGcMap(), m->GetGcMapLength());
 
     if (!pc) {
       // pc == NULL: m is either a native method or a phony method
diff --git a/test/StackWalk/stack_walk_jni.cc b/test/StackWalk/stack_walk_jni.cc
index 5b3921d..a967835 100644
--- a/test/StackWalk/stack_walk_jni.cc
+++ b/test/StackWalk/stack_walk_jni.cc
@@ -38,7 +38,7 @@
       CHECK_EQ(pc, 0u);
       return;
     }
-    verifier::PcToReferenceMap map(m);
+    verifier::PcToReferenceMap map(m->GetGcMap(), m->GetGcMapLength());
     const uint8_t* reg_bitmap = map.FindBitMap(m->ToDexPC(pc));
     MethodHelper mh(m);
     StringPiece m_name(mh.GetName());