Move rest of code related blobs from Method to oat

Change-Id: I55041b564ab65317c8b1f863005f20ba650a0322
diff --git a/build/Android.common.mk b/build/Android.common.mk
index ae713d0..605c48b 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -73,6 +73,7 @@
 	src/check_jni.cc \
 	src/class_linker.cc \
 	src/class_loader.cc \
+	src/compiled_method.cc \
 	src/compiler.cc \
 	src/compiler/Dataflow.cc \
 	src/compiler/Frontend.cc \
diff --git a/src/calling_convention.cc b/src/calling_convention.cc
index 17bfcff..5256ee1 100644
--- a/src/calling_convention.cc
+++ b/src/calling_convention.cc
@@ -17,7 +17,7 @@
 // Managed runtime calling convention
 
 ManagedRuntimeCallingConvention* ManagedRuntimeCallingConvention::Create(
-    Method* native_method, InstructionSet instruction_set) {
+    const Method* native_method, InstructionSet instruction_set) {
   if (instruction_set == kX86) {
     return new x86::X86ManagedRuntimeCallingConvention(native_method);
   } else {
@@ -67,7 +67,7 @@
 
 // JNI calling convention
 
-JniCallingConvention* JniCallingConvention::Create(Method* native_method,
+JniCallingConvention* JniCallingConvention::Create(const Method* native_method,
                                                InstructionSet instruction_set) {
   if (instruction_set == kX86) {
     return new x86::X86JniCallingConvention(native_method);
@@ -152,7 +152,7 @@
   }
 }
 
-size_t JniCallingConvention::NumberOfExtraArgumentsForJni(Method* method) {
+size_t JniCallingConvention::NumberOfExtraArgumentsForJni(const Method* method) {
   // The first argument is the JNIEnv*.
   // Static methods have an extra argument which is the jclass.
   return method->IsStatic() ? 2 : 1;
diff --git a/src/calling_convention.h b/src/calling_convention.h
index b57fd4d..3a7cf1e 100644
--- a/src/calling_convention.h
+++ b/src/calling_convention.h
@@ -42,10 +42,10 @@
   virtual ~CallingConvention() {}
 
  protected:
-  explicit CallingConvention(Method* method) : displacement_(0),
-                                               method_(method) {}
+  explicit CallingConvention(const Method* method)
+      : displacement_(0), method_(const_cast<Method*>(method)) {}
 
-  Method* GetMethod() const { return method_; }
+  const Method* GetMethod() const { return method_; }
 
   // The slot number for current calling_convention argument.
   // Note that each slot is 32-bit. When the current argument is bigger
@@ -74,8 +74,8 @@
 // | { Method* }             | <-- SP
 class ManagedRuntimeCallingConvention : public CallingConvention {
  public:
-  static ManagedRuntimeCallingConvention* Create(Method* native_method,
-                                                InstructionSet instruction_set);
+  static ManagedRuntimeCallingConvention* Create(const Method* native_method,
+                                                 InstructionSet instruction_set);
 
   size_t FrameSize();
 
@@ -97,7 +97,7 @@
   virtual ~ManagedRuntimeCallingConvention() {}
 
  protected:
-  explicit ManagedRuntimeCallingConvention(Method* method) :
+  explicit ManagedRuntimeCallingConvention(const Method* method) :
                                            CallingConvention(method) {}
 };
 
@@ -117,7 +117,7 @@
 // callee saves for frames above this one.
 class JniCallingConvention : public CallingConvention {
  public:
-  static JniCallingConvention* Create(Method* native_method,
+  static JniCallingConvention* Create(const Method* native_method,
                                       InstructionSet instruction_set);
 
   // Size of frame excluding space for outgoing args (its assumed Method* is
@@ -186,7 +186,7 @@
     kObjectOrClass = 1
   };
 
-  explicit JniCallingConvention(Method* native_method) :
+  explicit JniCallingConvention(const Method* native_method) :
       CallingConvention(native_method) {}
 
   // Number of stack slots for outgoing arguments, above which the SIRT is
@@ -194,7 +194,7 @@
   virtual size_t NumberOfOutgoingStackArgs() = 0;
 
  protected:
-  static size_t NumberOfExtraArgumentsForJni(Method* method);
+  static size_t NumberOfExtraArgumentsForJni(const Method* method);
 };
 
 }  // namespace art
diff --git a/src/calling_convention_arm.cc b/src/calling_convention_arm.cc
index e4f7b19f..29003a2 100644
--- a/src/calling_convention_arm.cc
+++ b/src/calling_convention_arm.cc
@@ -17,7 +17,7 @@
   return ArmManagedRegister::FromCoreRegister(IP);  // R12
 }
 
-static ManagedRegister ReturnRegisterForMethod(Method* method) {
+static ManagedRegister ReturnRegisterForMethod(const Method* method) {
   if (method->IsReturnAFloat()) {
     return ArmManagedRegister::FromCoreRegister(R0);
   } else if (method->IsReturnADouble()) {
@@ -99,7 +99,8 @@
 
 // JNI calling convention
 
-ArmJniCallingConvention::ArmJniCallingConvention(Method* method) : JniCallingConvention(method) {
+ArmJniCallingConvention::ArmJniCallingConvention(const Method* method)
+    : JniCallingConvention(method) {
   // Compute padding to ensure longs and doubles are not split in AAPCS
   // TODO: in terms of outgoing argument size this may be overly generous
   // due to padding appearing in the registers
@@ -159,7 +160,7 @@
 // in even register numbers and stack slots
 void ArmJniCallingConvention::Next() {
   JniCallingConvention::Next();
-  Method* method = GetMethod();
+  const Method* method = GetMethod();
   size_t arg_pos = itr_args_ - NumberOfExtraArgumentsForJni(method);
   if ((itr_args_ >= 2) &&
       (arg_pos < GetMethod()->NumArgs()) &&
@@ -184,7 +185,7 @@
 };
 ManagedRegister ArmJniCallingConvention::CurrentParamRegister() {
   CHECK_LT(itr_slots_, 4u);
-  Method* method = GetMethod();
+  const Method* method = GetMethod();
   int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni(method);
   if ((itr_args_ >= 2) && method->IsParamALongOrDouble(arg_pos)) {
     CHECK_EQ(itr_slots_, 2u);
@@ -202,7 +203,7 @@
 }
 
 size_t ArmJniCallingConvention::NumberOfOutgoingStackArgs() {
-  Method* method = GetMethod();
+  const Method* method = GetMethod();
   size_t static_args = method->IsStatic() ? 1 : 0;  // count jclass
   // regular argument parameters and this
   size_t param_args = method->NumArgs() +
diff --git a/src/calling_convention_arm.h b/src/calling_convention_arm.h
index 984250e..2a056a8 100644
--- a/src/calling_convention_arm.h
+++ b/src/calling_convention_arm.h
@@ -10,7 +10,7 @@
 
 class ArmManagedRuntimeCallingConvention : public ManagedRuntimeCallingConvention {
  public:
-  explicit ArmManagedRuntimeCallingConvention(Method* method) :
+  explicit ArmManagedRuntimeCallingConvention(const Method* method) :
                                      ManagedRuntimeCallingConvention(method) {}
   virtual ~ArmManagedRuntimeCallingConvention() {}
   // Calling convention
@@ -29,7 +29,7 @@
 
 class ArmJniCallingConvention : public JniCallingConvention {
  public:
-  explicit ArmJniCallingConvention(Method* method);
+  explicit ArmJniCallingConvention(const Method* method);
   virtual ~ArmJniCallingConvention() {}
   // Calling convention
   virtual ManagedRegister ReturnRegister();
diff --git a/src/calling_convention_x86.cc b/src/calling_convention_x86.cc
index ad7921d..da76e17 100644
--- a/src/calling_convention_x86.cc
+++ b/src/calling_convention_x86.cc
@@ -22,7 +22,7 @@
   return ManagedRegister::NoRegister();  // No free regs, so assembler uses push/pop
 }
 
-static ManagedRegister ReturnRegisterForMethod(Method* method) {
+static ManagedRegister ReturnRegisterForMethod(const Method* method) {
   if (method->IsReturnAFloatOrDouble()) {
     return X86ManagedRegister::FromX87Register(ST0);
   } else if (method->IsReturnALong()) {
diff --git a/src/calling_convention_x86.h b/src/calling_convention_x86.h
index cb27ef6..b796ba0 100644
--- a/src/calling_convention_x86.h
+++ b/src/calling_convention_x86.h
@@ -10,7 +10,7 @@
 
 class X86ManagedRuntimeCallingConvention : public ManagedRuntimeCallingConvention {
  public:
-  explicit X86ManagedRuntimeCallingConvention(Method* method) :
+  explicit X86ManagedRuntimeCallingConvention(const Method* method) :
                                      ManagedRuntimeCallingConvention(method) {}
   virtual ~X86ManagedRuntimeCallingConvention() {}
   // Calling convention
@@ -29,7 +29,7 @@
 
 class X86JniCallingConvention : public JniCallingConvention {
  public:
-  explicit X86JniCallingConvention(Method* method) :
+  explicit X86JniCallingConvention(const Method* method) :
                                    JniCallingConvention(method) {}
   virtual ~X86JniCallingConvention() {}
   // Calling convention
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 1ec482a..2cbac12 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -2034,13 +2034,13 @@
 
 bool ClassLinker::LinkInstanceFields(Class* klass) {
   CHECK(klass != NULL);
-  return LinkFields(klass, true);
+  return LinkFields(klass, false);
 }
 
 bool ClassLinker::LinkStaticFields(Class* klass) {
   CHECK(klass != NULL);
   size_t allocated_class_size = klass->GetClassSize();
-  bool success = LinkFields(klass, false);
+  bool success = LinkFields(klass, true);
   CHECK_EQ(allocated_class_size, klass->GetClassSize());
   return success;
 }
@@ -2068,26 +2068,26 @@
   }
 };
 
-bool ClassLinker::LinkFields(Class* klass, bool instance) {
+bool ClassLinker::LinkFields(Class* klass, bool is_static) {
   size_t num_fields =
-      instance ? klass->NumInstanceFields() : klass->NumStaticFields();
+      is_static ? klass->NumStaticFields() : klass->NumInstanceFields();
 
   ObjectArray<Field>* fields =
-      instance ? klass->GetIFields() : klass->GetSFields();
+      is_static ? klass->GetSFields() : klass->GetIFields();
 
   // Initialize size and field_offset
   size_t size;
   MemberOffset field_offset(0);
-  if (instance) {
+  if (is_static) {
+    size = klass->GetClassSize();
+    field_offset = Class::FieldsOffset();
+  } else {
     Class* super_class = klass->GetSuperClass();
     if (super_class != NULL) {
       CHECK(super_class->IsResolved());
       field_offset = MemberOffset(super_class->GetObjectSize());
     }
     size = field_offset.Uint32Value();
-  } else {
-    size = klass->GetClassSize();
-    field_offset = Class::FieldsOffset();
   }
 
   CHECK_EQ(num_fields == 0, fields == NULL);
@@ -2161,7 +2161,7 @@
   }
 
   // We lie to the GC about the java.lang.ref.Reference.referent field, so it doesn't scan it.
-  if (instance && klass->GetDescriptor()->Equals("Ljava/lang/ref/Reference;")) {
+  if (!is_static && klass->GetDescriptor()->Equals("Ljava/lang/ref/Reference;")) {
     // We know there are no non-reference fields in the Reference classes, and we know
     // that 'referent' is alphabetically last, so this is easy...
     CHECK_EQ(num_reference_fields, num_fields);
@@ -2176,7 +2176,7 @@
   for (size_t i = 0; i < num_fields; i++) {
     Field* field = fields->Get(i);
     if (false) {  // enable to debug field layout
-      LOG(INFO) << "LinkFields: " << (instance ? "instance" : "static")
+      LOG(INFO) << "LinkFields: " << (is_static ? "static" : "instance")
                 << " class=" << PrettyClass(klass)
                 << " field=" << PrettyField(field)
                 << " offset=" << field->GetField32(MemberOffset(Field::OffsetOffset()), false);
@@ -2201,14 +2201,14 @@
 #endif
   size = field_offset.Uint32Value();
   // Update klass
-  if (instance) {
+  if (is_static) {
+    klass->SetNumReferenceStaticFields(num_reference_fields);
+    klass->SetClassSize(size);
+  } else {
     klass->SetNumReferenceInstanceFields(num_reference_fields);
     if (!klass->IsVariableSize()) {
       klass->SetObjectSize(size);
     }
-  } else {
-    klass->SetNumReferenceStaticFields(num_reference_fields);
-    klass->SetClassSize(size);
   }
   return true;
 }
@@ -2226,20 +2226,20 @@
       return;
     }
   }
-  CreateReferenceOffsets(klass, true, reference_offsets);
+  CreateReferenceOffsets(klass, false, reference_offsets);
 }
 
 void ClassLinker::CreateReferenceStaticOffsets(Class* klass) {
-  CreateReferenceOffsets(klass, false, 0);
+  CreateReferenceOffsets(klass, true, 0);
 }
 
-void ClassLinker::CreateReferenceOffsets(Class* klass, bool instance,
+void ClassLinker::CreateReferenceOffsets(Class* klass, bool is_static,
                                          uint32_t reference_offsets) {
   size_t num_reference_fields =
-      instance ? klass->NumReferenceInstanceFieldsDuringLinking()
-               : klass->NumReferenceStaticFieldsDuringLinking();
+      is_static ? klass->NumReferenceStaticFieldsDuringLinking()
+                : klass->NumReferenceInstanceFieldsDuringLinking();
   const ObjectArray<Field>* fields =
-      instance ? klass->GetIFields() : klass->GetSFields();
+      is_static ? klass->GetSFields() : klass->GetIFields();
   // All of the fields that contain object references are guaranteed
   // to be at the beginning of the fields list.
   for (size_t i = 0; i < num_reference_fields; ++i) {
@@ -2258,10 +2258,10 @@
     }
   }
   // Update fields in klass
-  if (instance) {
-    klass->SetReferenceInstanceOffsets(reference_offsets);
-  } else {
+  if (is_static) {
     klass->SetReferenceStaticOffsets(reference_offsets);
+  } else {
+    klass->SetReferenceInstanceOffsets(reference_offsets);
   }
 }
 
diff --git a/src/class_linker.h b/src/class_linker.h
index 304d37f..6d17a10 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -291,12 +291,12 @@
 
   bool LinkStaticFields(Class* klass);
   bool LinkInstanceFields(Class* klass);
-  bool LinkFields(Class *klass, bool instance);
+  bool LinkFields(Class *klass, bool is_static);
 
 
   void CreateReferenceInstanceOffsets(Class* klass);
   void CreateReferenceStaticOffsets(Class* klass);
-  void CreateReferenceOffsets(Class *klass, bool instance,
+  void CreateReferenceOffsets(Class *klass, bool is_static,
                               uint32_t reference_offsets);
 
   // For use by ImageWriter to find DexCaches for its roots
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 9ae64a3..025f9e3 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -304,7 +304,9 @@
 
 template <typename T>
 struct CheckOffsets {
-  bool instance;
+  CheckOffsets(bool is_static, const char* class_descriptor)
+      : is_static(is_static), class_descriptor(class_descriptor) {}
+  bool is_static;
   std::string class_descriptor;
   std::vector<CheckOffset> offsets;
 
@@ -314,8 +316,8 @@
 
     bool error = false;
 
-    if (!klass->IsClassClass() && instance) {
-      size_t expected_size = instance ? klass->GetObjectSize() : klass->GetClassSize();
+    if (!klass->IsClassClass() && !is_static) {
+      size_t expected_size = is_static ? klass->GetClassSize(): klass->GetObjectSize();
       if (sizeof(T) != expected_size) {
         LG << "Class size mismatch:"
            << " class=" << class_descriptor
@@ -325,7 +327,7 @@
       }
     }
 
-    size_t num_fields = instance ? klass->NumInstanceFields() : klass->NumStaticFields();
+    size_t num_fields = is_static ? klass->NumStaticFields() : klass->NumInstanceFields();
     if (offsets.size() != num_fields) {
       LG << "Field count mismatch:"
          << " class=" << class_descriptor
@@ -335,7 +337,7 @@
     }
 
     for (size_t i = 0; i < offsets.size(); i++) {
-      Field* field = instance ? klass->GetInstanceField(i) : klass->GetStaticField(i);
+      Field* field = is_static ? klass->GetStaticField(i) : klass->GetInstanceField(i);
       if (!field->GetName()->Equals(offsets[i].java_name)) {
         error = true;
       }
@@ -343,7 +345,7 @@
     if (error) {
       for (size_t i = 0; i < offsets.size(); i++) {
         CheckOffset& offset = offsets[i];
-        Field* field = instance ? klass->GetInstanceField(i) : klass->GetStaticField(i);
+        Field* field = is_static ? klass->GetStaticField(i) : klass->GetInstanceField(i);
         if (!field->GetName()->Equals(offsets[i].java_name)) {
           LG << "JAVA FIELD ORDER MISMATCH NEXT LINE:";
         }
@@ -356,7 +358,7 @@
 
     for (size_t i = 0; i < offsets.size(); i++) {
       CheckOffset& offset = offsets[i];
-      Field* field = instance ? klass->GetInstanceField(i) : klass->GetStaticField(i);
+      Field* field = is_static ? klass->GetStaticField(i) : klass->GetInstanceField(i);
       if (field->GetOffset().Uint32Value() != offset.cpp_offset) {
         error = true;
       }
@@ -364,7 +366,7 @@
     if (error) {
       for (size_t i = 0; i < offsets.size(); i++) {
         CheckOffset& offset = offsets[i];
-        Field* field = instance ? klass->GetInstanceField(i) : klass->GetStaticField(i);
+        Field* field = is_static ? klass->GetStaticField(i) : klass->GetInstanceField(i);
         if (field->GetOffset().Uint32Value() != offset.cpp_offset) {
           LG << "OFFSET MISMATCH NEXT LINE:";
         }
@@ -375,15 +377,16 @@
 
     return !error;
   };
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(CheckOffsets);
 };
 
 // Note that ClassLinkerTest.ValidateFieldOrderOfJavaCppUnionClasses
 // is first since if it is failing, others are unlikely to succeed.
 
 struct ObjectOffsets : public CheckOffsets<Object> {
-  ObjectOffsets() {
-    instance = true;
-    class_descriptor = "Ljava/lang/Object;";
+  ObjectOffsets() : CheckOffsets<Object>(false, "Ljava/lang/Object;") {
 
     // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Object, klass_),   "shadow$_klass_"));
@@ -394,17 +397,14 @@
 };
 
 struct AccessibleObjectOffsets : public CheckOffsets<AccessibleObject> {
-  AccessibleObjectOffsets() {
-    instance = true;
-    class_descriptor = "Ljava/lang/reflect/AccessibleObject;";
+  AccessibleObjectOffsets()
+      : CheckOffsets<AccessibleObject>(false, "Ljava/lang/reflect/AccessibleObject;") {
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AccessibleObject, java_flag_), "flag"));
   };
 };
 
 struct FieldOffsets : public CheckOffsets<Field> {
-  FieldOffsets() {
-    instance = true;
-    class_descriptor = "Ljava/lang/reflect/Field;";
+  FieldOffsets() : CheckOffsets<Field>(false, "Ljava/lang/reflect/Field;") {
 
     // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, declaring_class_),               "declaringClass"));
@@ -422,9 +422,7 @@
 };
 
 struct MethodOffsets : public CheckOffsets<Method> {
-  MethodOffsets() {
-    instance = true;
-    class_descriptor = "Ljava/lang/reflect/Method;";
+  MethodOffsets() : CheckOffsets<Method>(false, "Ljava/lang/reflect/Method;") {
 
     // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, declaring_class_),                      "declaringClass"));
@@ -436,20 +434,16 @@
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, name_),                                 "name"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_parameter_types_),                 "parameterTypes"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_return_type_),                     "returnType"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, code_array_),                           "shadow$_code_array_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_code_and_direct_methods_),    "shadow$_dex_cache_code_and_direct_methods_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_initialized_static_storage_), "shadow$_dex_cache_initialized_static_storage_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_fields_),            "shadow$_dex_cache_resolved_fields_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_methods_),           "shadow$_dex_cache_resolved_methods_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_types_),             "shadow$_dex_cache_resolved_types_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_strings_),                    "shadow$_dex_cache_strings_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, invoke_stub_array_),                    "shadow$_invoke_stub_array_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, mapping_table_),                        "shadow$_mapping_table_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, register_map_data_),                    "shadow$_register_map_data_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, register_map_header_),                  "shadow$_register_map_header_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, shorty_),                               "shadow$_shorty_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, signature_),                            "shadow$_signature_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, vmap_table_),                           "shadow$_vmap_table_"));
 
     // alphabetical 32-bit
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_generic_types_are_initialized_),   "genericTypesAreInitialized"));
@@ -461,6 +455,7 @@
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, frame_size_in_bytes_),                  "shadow$_frame_size_in_bytes_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, invoke_stub_),                          "shadow$_invoke_stub_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_return_type_idx_),                 "shadow$_java_return_type_idx_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, mapping_table_),                        "shadow$_mapping_table_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, method_index_),                         "shadow$_method_index_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, native_method_),                        "shadow$_native_method_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, num_ins_),                              "shadow$_num_ins_"));
@@ -468,6 +463,7 @@
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, num_registers_),                        "shadow$_num_registers_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, proto_idx_),                            "shadow$_proto_idx_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, return_pc_offset_in_bytes_),            "shadow$_return_pc_offset_in_bytes_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, vmap_table_),                           "shadow$_vmap_table_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_slot_),                            "slot"));
   };
 };
@@ -480,9 +476,7 @@
 };
 
 struct ClassOffsets : public CheckOffsets<Class> {
-  ClassOffsets() {
-    instance = true;
-    class_descriptor = "Ljava/lang/Class;";
+  ClassOffsets() : CheckOffsets<Class>(false, "Ljava/lang/Class;") {
 
     // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, name_),                          "name"));
@@ -518,9 +512,7 @@
 };
 
 struct StringOffsets : public CheckOffsets<String> {
-  StringOffsets() {
-    instance = true;
-    class_descriptor = "Ljava/lang/String;";
+  StringOffsets() : CheckOffsets<String>(false, "Ljava/lang/String;") {
 
     // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(String, array_),     "value"));
@@ -533,9 +525,7 @@
 };
 
 struct ThrowableOffsets : public CheckOffsets<Throwable> {
-  ThrowableOffsets() {
-    instance = true;
-    class_descriptor = "Ljava/lang/Throwable;";
+  ThrowableOffsets() : CheckOffsets<Throwable>(false, "Ljava/lang/Throwable;") {
 
     // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Throwable, cause_),                 "cause"));
@@ -547,9 +537,7 @@
 };
 
 struct StackTraceElementOffsets : public CheckOffsets<StackTraceElement> {
-  StackTraceElementOffsets() {
-    instance = true;
-    class_descriptor = "Ljava/lang/StackTraceElement;";
+  StackTraceElementOffsets() : CheckOffsets<StackTraceElement>(false, "Ljava/lang/StackTraceElement;") {
 
     // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(StackTraceElement, declaring_class_), "declaringClass"));
@@ -560,9 +548,7 @@
 };
 
 struct ClassLoaderOffsets : public CheckOffsets<ClassLoader> {
-  ClassLoaderOffsets() {
-    instance = true;
-    class_descriptor = "Ljava/lang/ClassLoader;";
+  ClassLoaderOffsets() : CheckOffsets<ClassLoader>(false, "Ljava/lang/ClassLoader;") {
 
     // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(ClassLoader, packages_), "packages"));
@@ -571,9 +557,8 @@
 };
 
 struct BaseDexClassLoaderOffsets : public CheckOffsets<BaseDexClassLoader> {
-  BaseDexClassLoaderOffsets() {
-    instance = true;
-    class_descriptor = "Ldalvik/system/BaseDexClassLoader;";
+  BaseDexClassLoaderOffsets()
+    : CheckOffsets<BaseDexClassLoader>(false, "Ldalvik/system/BaseDexClassLoader;") {
 
     // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(BaseDexClassLoader, original_path_), "originalPath"));
@@ -582,16 +567,12 @@
 };
 
 struct PathClassLoaderOffsets : public CheckOffsets<PathClassLoader> {
-  PathClassLoaderOffsets() {
-    instance = true;
-    class_descriptor = "Ldalvik/system/PathClassLoader;";
-  };
+  PathClassLoaderOffsets()
+    : CheckOffsets<PathClassLoader>(false, "Ldalvik/system/PathClassLoader;") {};
 };
 
 struct ClassClassOffsets : public CheckOffsets<ClassClass> {
-  ClassClassOffsets() {
-    instance = false;
-    class_descriptor = "Ljava/lang/Class;";
+  ClassClassOffsets() : CheckOffsets<ClassClass>(true, "Ljava/lang/Class;") {
 
     // padding 32-bit
     CHECK_EQ(OFFSETOF_MEMBER(ClassClass, padding_) + 4,
@@ -603,9 +584,7 @@
 };
 
 struct StringClassOffsets : public CheckOffsets<StringClass> {
-  StringClassOffsets() {
-    instance = false;
-    class_descriptor = "Ljava/lang/String;";
+  StringClassOffsets() : CheckOffsets<StringClass>(true, "Ljava/lang/String;") {
 
     // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(StringClass, ASCII_),                  "ASCII"));
@@ -620,9 +599,7 @@
 };
 
 struct FieldClassOffsets : public CheckOffsets<FieldClass> {
-  FieldClassOffsets() {
-    instance = false;
-    class_descriptor = "Ljava/lang/reflect/Field;";
+  FieldClassOffsets() : CheckOffsets<FieldClass>(true, "Ljava/lang/reflect/Field;") {
 
     // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(FieldClass, ORDER_BY_NAME_AND_DECLARING_CLASS_), "ORDER_BY_NAME_AND_DECLARING_CLASS"));
@@ -640,9 +617,7 @@
 };
 
 struct MethodClassOffsets : public CheckOffsets<MethodClass> {
-  MethodClassOffsets() {
-    instance = false;
-    class_descriptor = "Ljava/lang/reflect/Method;";
+  MethodClassOffsets() : CheckOffsets<MethodClass>(true, "Ljava/lang/reflect/Method;") {
 
     // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(MethodClass, ORDER_BY_SIGNATURE_), "ORDER_BY_SIGNATURE"));
diff --git a/src/common_test.h b/src/common_test.h
index 84b97e9..1039ff1 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -16,6 +16,7 @@
 #include "file.h"
 #include "gtest/gtest.h"
 #include "heap.h"
+#include "oat_file.h"
 #include "os.h"
 #include "runtime.h"
 #include "stl_util.h"
@@ -79,10 +80,68 @@
 
 class CommonTest : public testing::Test {
  public:
-  static void MakeExecutable(const ByteArray* byte_array) {
-    uintptr_t data = reinterpret_cast<uintptr_t>(byte_array->GetData());
+
+  static void MakeExecutable(const ByteArray* code_array) {
+    CHECK(code_array != NULL);
+    MakeExecutable(code_array->GetData(), code_array->GetLength());
+  }
+
+  static void MakeExecutable(const std::vector<uint8_t>& code) {
+    CHECK_NE(code.size(), 0U);
+    MakeExecutable(&code[0], code.size());
+  }
+
+  void MakeExecutable(Method* method) {
+    CHECK(method != NULL);
+
+    const CompiledInvokeStub* compiled_invoke_stub = compiler_->GetCompiledInvokeStub(method);
+    CHECK(compiled_invoke_stub != NULL) << PrettyMethod(method);
+    const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
+    MakeExecutable(invoke_stub);
+    const Method::InvokeStub* method_invoke_stub
+        = reinterpret_cast<const Method::InvokeStub*>(&invoke_stub[0]);
+    LOG(INFO) << "MakeExecutable " << PrettyMethod(method)
+              << " invoke_stub=" << reinterpret_cast<void*>(method_invoke_stub);
+
+    if (!method->IsAbstract()) {
+      const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method);
+      CHECK(compiled_method != NULL) << PrettyMethod(method);
+      const std::vector<uint8_t>& code = compiled_method->GetCode();
+      MakeExecutable(code);
+      const void* method_code
+          = CompiledMethod::CodePointer(&code[0], compiled_method->GetInstructionSet());
+      LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code;
+      OatFile::OatMethod oat_method(method_code,
+                                    compiled_method->GetFrameSizeInBytes(),
+                                    compiled_method->GetReturnPcOffsetInBytes(),
+                                    compiled_method->GetCoreSpillMask(),
+                                    compiled_method->GetFpSpillMask(),
+                                    &compiled_method->GetMappingTable()[0],
+                                    &compiled_method->GetVmapTable()[0],
+                                    method_invoke_stub);
+      oat_method.LinkMethod(method);
+    } else {
+      MakeExecutable(runtime_->GetAbstractMethodErrorStubArray());
+      const void* method_code = runtime_->GetAbstractMethodErrorStubArray()->GetData();
+      LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code;
+      OatFile::OatMethod oat_method(method_code,
+                                    kStackAlignment,
+                                    0,
+                                    0,
+                                    0,
+                                    NULL,
+                                    NULL,
+                                    method_invoke_stub);
+      oat_method.LinkMethod(method);
+    }
+  }
+
+  static void MakeExecutable(const void* code_start, size_t code_length) {
+    CHECK(code_start != NULL);
+    CHECK_NE(code_length, 0U);
+    uintptr_t data = reinterpret_cast<uintptr_t>(code_start);
     uintptr_t base = RoundDown(data, kPageSize);
-    uintptr_t limit = RoundUp(data + byte_array->GetLength(), kPageSize);
+    uintptr_t limit = RoundUp(data + code_length, kPageSize);
     uintptr_t len = limit - base;
     int result = mprotect(reinterpret_cast<void*>(base), len, PROT_READ | PROT_WRITE | PROT_EXEC);
     CHECK_EQ(result, 0);
@@ -274,9 +333,9 @@
   void CompileMethod(Method* method) {
     CHECK(method != NULL);
     compiler_->CompileOne(method);
+    MakeExecutable(method);
+
     MakeExecutable(runtime_->GetJniStubArray());
-    MakeExecutable(method->GetCodeArray());
-    MakeExecutable(method->GetInvokeStubArray());
   }
 
   void CompileDirectMethod(const ClassLoader* class_loader,
diff --git a/src/compiled_method.cc b/src/compiled_method.cc
new file mode 100644
index 0000000..2846ab3
--- /dev/null
+++ b/src/compiled_method.cc
@@ -0,0 +1,157 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include "compiled_method.h"
+
+namespace art {
+
+CompiledMethod::CompiledMethod(InstructionSet instruction_set,
+                               std::vector<short>& short_code,
+                               const size_t frame_size_in_bytes,
+                               const size_t return_pc_offset_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) {
+  CHECK_NE(short_code.size(), 0U);
+
+  size_t code_byte_count = short_code.size() * sizeof(short_code[0]);
+  std::vector<uint8_t> byte_code(code_byte_count);
+  memcpy(&byte_code[0], &short_code[0], code_byte_count);
+
+  std::vector<uint32_t> length_prefixed_mapping_table;
+  length_prefixed_mapping_table.push_back(mapping_table.size());
+  length_prefixed_mapping_table.insert(length_prefixed_mapping_table.end(),
+                                       mapping_table.begin(),
+                                       mapping_table.end());
+  DCHECK_EQ(mapping_table.size() + 1, length_prefixed_mapping_table.size());
+
+  std::vector<uint16_t> length_prefixed_vmap_table;
+  length_prefixed_vmap_table.push_back(vmap_table.size());
+  length_prefixed_vmap_table.insert(length_prefixed_vmap_table.end(),
+                                    vmap_table.begin(),
+                                    vmap_table.end());
+  DCHECK_EQ(vmap_table.size() + 1, length_prefixed_vmap_table.size());
+
+  instruction_set_ = instruction_set;
+  code_ = byte_code;
+  frame_size_in_bytes_ = frame_size_in_bytes;
+  return_pc_offset_in_bytes_ = return_pc_offset_in_bytes;
+  core_spill_mask_ = core_spill_mask;
+  fp_spill_mask_ = fp_spill_mask;
+  mapping_table_ = length_prefixed_mapping_table;
+  vmap_table_ = length_prefixed_vmap_table;
+}
+
+CompiledMethod::CompiledMethod(InstructionSet instruction_set,
+                               std::vector<uint8_t>& code,
+                               const size_t frame_size_in_bytes,
+                               const size_t return_pc_offset_in_bytes,
+                               const uint32_t core_spill_mask,
+                               const uint32_t fp_spill_mask) {
+  CHECK_NE(code.size(), 0U);
+
+  instruction_set_ = instruction_set;
+  code_ = code;
+  frame_size_in_bytes_ = frame_size_in_bytes;
+  return_pc_offset_in_bytes_ = return_pc_offset_in_bytes;
+  core_spill_mask_ = core_spill_mask;
+  fp_spill_mask_ = fp_spill_mask;
+}
+
+CompiledMethod::~CompiledMethod() {}
+
+InstructionSet CompiledMethod::GetInstructionSet() const {
+  return instruction_set_;
+}
+
+const std::vector<uint8_t>& CompiledMethod::GetCode() const {
+  return code_;
+}
+
+size_t CompiledMethod::GetFrameSizeInBytes() const {
+  return frame_size_in_bytes_;
+}
+
+size_t CompiledMethod::GetReturnPcOffsetInBytes() const {
+  return return_pc_offset_in_bytes_;
+}
+
+uint32_t CompiledMethod::GetCoreSpillMask() const {
+  return core_spill_mask_;
+}
+
+uint32_t CompiledMethod::GetFpSpillMask() const {
+  return fp_spill_mask_;
+}
+
+const std::vector<uint32_t>& CompiledMethod::GetMappingTable() const {
+  return mapping_table_;
+}
+
+const std::vector<uint16_t>& CompiledMethod::GetVmapTable() const {
+  return vmap_table_;
+}
+
+uint32_t CompiledMethod::AlignCode(uint32_t offset) const {
+  return AlignCode(offset, instruction_set_);
+}
+
+uint32_t CompiledMethod::AlignCode(uint32_t offset, InstructionSet instruction_set) {
+  switch (instruction_set) {
+    case kArm:
+    case kThumb2:
+      return RoundUp(offset, kArmAlignment);
+    case kX86:
+      return offset;
+    default:
+      LOG(FATAL) << "Unknown InstructionSet " << (int) instruction_set;
+      return 0;
+  }
+}
+
+size_t CompiledMethod::CodeDelta() const {
+  switch (instruction_set_) {
+    case kArm:
+    case kX86:
+      return 0;
+    case kThumb2: {
+      // +1 to set the low-order bit so a BLX will switch to Thumb mode
+      return 1;
+    }
+    default:
+      LOG(FATAL) << "Unknown InstructionSet " << (int) instruction_set_;
+      return NULL;
+  }
+}
+
+const void* CompiledMethod::CodePointer(const void* code_pointer,
+                                        InstructionSet instruction_set) {
+  switch (instruction_set) {
+    case kArm:
+    case kX86:
+      return code_pointer;
+    case kThumb2: {
+      uintptr_t address = reinterpret_cast<uintptr_t>(code_pointer);
+      // Set the low-order bit so a BLX will switch to Thumb mode
+      address |= 0x1;
+      return reinterpret_cast<const void*>(address);
+    }
+    default:
+      LOG(FATAL) << "Unknown InstructionSet " << (int) instruction_set;
+      return NULL;
+  }
+}
+
+
+CompiledInvokeStub::CompiledInvokeStub(std::vector<uint8_t>& code) {
+  CHECK_NE(code.size(), 0U);
+  code_ = code;
+}
+
+CompiledInvokeStub::~CompiledInvokeStub() {}
+
+const std::vector<uint8_t>& CompiledInvokeStub::GetCode() const {
+  return code_;
+}
+
+}  // namespace art
diff --git a/src/compiled_method.h b/src/compiled_method.h
new file mode 100644
index 0000000..e228ca8
--- /dev/null
+++ b/src/compiled_method.h
@@ -0,0 +1,83 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_COMPILED_METHOD_H_
+#define ART_SRC_COMPILED_METHOD_H_
+
+#include <vector>
+
+#include "constants.h"
+#include "utils.h"
+
+namespace art {
+
+class CompiledMethod {
+ public:
+  // Create an CompiledMethod from the oatCompileMethod
+  CompiledMethod(InstructionSet instruction_set,
+                 std::vector<short>& code,
+                 const size_t frame_size_in_bytes,
+                 const size_t return_pc_offset_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);
+
+  // Create an CompiledMethod from the JniCompiler
+  CompiledMethod(InstructionSet instruction_set,
+                 std::vector<uint8_t>& code,
+                 const size_t frame_size_in_bytes,
+                 const size_t return_pc_offset_in_bytes,
+                 const uint32_t core_spill_mask,
+                 const uint32_t fp_spill_mask);
+
+  ~CompiledMethod();
+
+  InstructionSet GetInstructionSet() const;
+  const std::vector<uint8_t>& GetCode() const;
+  size_t GetFrameSizeInBytes() const;
+  size_t GetReturnPcOffsetInBytes() const;
+  uint32_t GetCoreSpillMask() const;
+  uint32_t GetFpSpillMask() const;
+  const std::vector<uint32_t>& GetMappingTable() const;
+  const std::vector<uint16_t>& GetVmapTable() 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.
+  uint32_t AlignCode(uint32_t offset) const;
+  static uint32_t AlignCode(uint32_t offset, InstructionSet instruction_set);
+
+  // returns the difference between the code address and a usable PC.
+  // mainly to cope with kThumb2 where the lower bit must be set.
+  size_t CodeDelta() const;
+
+  // Returns a pointer suitable for invoking the code at the argument
+  // code_pointer address.  Mainly to cope with kThumb2 where the
+  // lower bit must be set to indicate Thumb mode.
+  static const void* CodePointer(const void* code_pointer,
+                                 InstructionSet instruction_set);
+
+ private:
+  InstructionSet instruction_set_;
+  std::vector<uint8_t> code_;
+  size_t frame_size_in_bytes_;
+  size_t return_pc_offset_in_bytes_;
+  uint32_t core_spill_mask_;
+  uint32_t fp_spill_mask_;
+  std::vector<uint32_t> mapping_table_;
+  std::vector<uint16_t> vmap_table_;
+};
+
+class CompiledInvokeStub {
+ public:
+  CompiledInvokeStub(std::vector<uint8_t>& code);
+  ~CompiledInvokeStub();
+  const std::vector<uint8_t>& GetCode() const;
+ private:
+  std::vector<uint8_t> code_;
+};
+
+}  // namespace art
+
+#endif  // ART_SRC_COMPILED_METHOD_H_
+
diff --git a/src/compiler.cc b/src/compiler.cc
index 3b92267..3b98ea0 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -10,28 +10,37 @@
 #include "dex_cache.h"
 #include "jni_compiler.h"
 #include "jni_internal.h"
+#include "oat_file.h"
 #include "runtime.h"
+#include "stl_util.h"
 
-extern bool oatCompileMethod(const art::Compiler& compiler, art::Method*, art::InstructionSet);
+extern art::CompiledMethod* oatCompileMethod(const art::Compiler& compiler,
+                                             const art::Method*,
+                                             art::InstructionSet);
 
 namespace art {
 
 namespace arm {
   ByteArray* CreateAbstractMethodErrorStub();
-  void ArmCreateInvokeStub(Method* method);
+  CompiledInvokeStub* ArmCreateInvokeStub(const Method* method);
   ByteArray* ArmCreateResolutionTrampoline(Runtime::TrampolineType type);
 }
 namespace x86 {
   ByteArray* CreateAbstractMethodErrorStub();
-  void X86CreateInvokeStub(Method* method);
+  CompiledInvokeStub* X86CreateInvokeStub(const Method* method);
   ByteArray* X86CreateResolutionTrampoline(Runtime::TrampolineType type);
 }
 
-Compiler::Compiler(InstructionSet insns) : instruction_set_(insns), jni_compiler_(insns),
-    verbose_(false) {
+Compiler::Compiler(InstructionSet instruction_set)
+    : instruction_set_(instruction_set), jni_compiler_(instruction_set), verbose_(false) {
   CHECK(!Runtime::Current()->IsStarted());
 }
 
+Compiler::~Compiler() {
+  STLDeleteValues(&compiled_methods_);
+  STLDeleteValues(&compiled_invoke_stubs_);
+}
+
 ByteArray* Compiler::CreateResolutionStub(InstructionSet instruction_set,
                                           Runtime::TrampolineType type) {
   if (instruction_set == kX86) {
@@ -62,7 +71,7 @@
   SetCodeAndDirectMethods(class_loader);
 }
 
-void Compiler::CompileOne(Method* method) {
+void Compiler::CompileOne(const Method* method) {
   DCHECK(!Runtime::Current()->IsStarted());
   const ClassLoader* class_loader = method->GetDeclaringClass()->GetClassLoader();
   Resolve(class_loader);
@@ -276,7 +285,7 @@
   }
 }
 
-void Compiler::CompileClass(Class* klass) {
+void Compiler::CompileClass(const Class* klass) {
   for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
     CompileMethod(klass->GetDirectMethod(i));
   }
@@ -285,35 +294,50 @@
   }
 }
 
-void Compiler::CompileMethod(Method* method) {
+void Compiler::CompileMethod(const Method* method) {
   if (method->IsNative()) {
-    jni_compiler_.Compile(method);
-    // unregister will install the stub to lookup via dlsym
-    // TODO: this is only necessary for tests
-    if (!method->IsRegistered()) {
-      method->UnregisterNative();
-    }
+    CompiledMethod* compiled_method = jni_compiler_.Compile(method);
+    CHECK(compiled_method != NULL);
+    compiled_methods_[method] = compiled_method;
+    DCHECK_EQ(1U, compiled_methods_.count(method));
+    DCHECK(GetCompiledMethod(method) != NULL) << PrettyMethod(method);
   } else if (method->IsAbstract()) {
-    ByteArray* abstract_method_error_stub = Runtime::Current()->GetAbstractMethodErrorStubArray();
-    if (instruction_set_ == kX86) {
-      method->SetCodeArray(abstract_method_error_stub, kX86);
-    } else {
-      CHECK(instruction_set_ == kArm || instruction_set_ == kThumb2);
-      method->SetCodeArray(abstract_method_error_stub, kArm);
-    }
   } else {
-    oatCompileMethod(*this, method, kThumb2);
+    CompiledMethod* compiled_method = oatCompileMethod(*this, method, kThumb2);
+    CHECK(compiled_method != NULL);
+    compiled_methods_[method] = compiled_method;
+    DCHECK_EQ(1U, compiled_methods_.count(method));
+    DCHECK(GetCompiledMethod(method) != NULL) << PrettyMethod(method);
   }
-  CHECK(method->GetCode() != NULL) << PrettyMethod(method);
 
+  CompiledInvokeStub* compiled_invoke_stub = NULL;
   if (instruction_set_ == kX86) {
-    art::x86::X86CreateInvokeStub(method);
+    compiled_invoke_stub = art::x86::X86CreateInvokeStub(method);
   } else {
     CHECK(instruction_set_ == kArm || instruction_set_ == kThumb2);
     // Generates invocation stub using ARM instruction set
-    art::arm::ArmCreateInvokeStub(method);
+    compiled_invoke_stub = art::arm::ArmCreateInvokeStub(method);
   }
-  CHECK(method->GetInvokeStub() != NULL);
+  CHECK(compiled_invoke_stub != NULL);
+  compiled_invoke_stubs_[method] = compiled_invoke_stub;
+}
+
+const CompiledMethod* Compiler::GetCompiledMethod(const Method* method) const {
+    MethodTable::const_iterator it = compiled_methods_.find(method);
+  if (it == compiled_methods_.end()) {
+    return NULL;
+  }
+  CHECK(it->second != NULL);
+  return it->second;
+}
+
+const CompiledInvokeStub* Compiler::GetCompiledInvokeStub(const Method* method) const {
+  InvokeStubTable::const_iterator it = compiled_invoke_stubs_.find(method);
+  if (it == compiled_invoke_stubs_.end()) {
+    return NULL;
+  }
+  CHECK(it->second != NULL);
+  return it->second;
 }
 
 void Compiler::SetCodeAndDirectMethods(const ClassLoader* class_loader) {
@@ -332,17 +356,10 @@
   CodeAndDirectMethods* code_and_direct_methods = dex_cache->GetCodeAndDirectMethods();
   for (size_t i = 0; i < dex_cache->NumResolvedMethods(); i++) {
     Method* method = dex_cache->GetResolvedMethod(i);
-    if ((method == NULL) || (method->IsStatic() && !method->GetDeclaringClass()->IsInitialized())) {
+    if (method == NULL || method->IsDirect()) {
       Runtime::TrampolineType type = Runtime::GetTrampolineType(method);
       ByteArray* res_trampoline = runtime->GetResolutionStubArray(type);
-      if (instruction_set_ == kX86) {
-        code_and_direct_methods->SetResolvedDirectMethodTrampoline(i, res_trampoline, kX86);
-      } else {
-        CHECK(instruction_set_ == kArm || instruction_set_ == kThumb2);
-        code_and_direct_methods->SetResolvedDirectMethodTrampoline(i, res_trampoline, kArm);
-      }
-    } else if (method->IsDirect()) {
-      code_and_direct_methods->SetResolvedDirectMethod(i, method);
+      code_and_direct_methods->SetResolvedDirectMethodTrampoline(i, res_trampoline);
     } else {
       // TODO: we currently leave the entry blank for resolved
       // non-direct methods.  we could put in an error stub.
diff --git a/src/compiler.h b/src/compiler.h
index 0f6f02f..6059a2a 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -3,30 +3,37 @@
 #ifndef ART_SRC_COMPILER_H_
 #define ART_SRC_COMPILER_H_
 
+#include "compiled_method.h"
 #include "constants.h"
 #include "dex_file.h"
 #include "jni_compiler.h"
+#include "oat_file.h"
 #include "object.h"
 #include "runtime.h"
-
-int oatVRegOffsetFromMethod(art::Method* method, int reg);
+#include "unordered_map.h"
 
 namespace art {
 
 class Compiler {
  public:
-  explicit Compiler(InstructionSet insns);
+  explicit Compiler(InstructionSet instruction_set);
+
+  ~Compiler();
 
   // Compile all Methods of all the Classes of all the DexFiles that are part of a ClassLoader.
   void CompileAll(const ClassLoader* class_loader);
 
   // Compile a single Method
-  void CompileOne(Method* method);
+  void CompileOne(const Method* method);
 
   void SetVerbose(bool verbose) {
     verbose_ = verbose;
   }
 
+  InstructionSet GetInstructionSet() const {
+    return instruction_set_;
+  }
+
   bool IsVerbose() const {
     return verbose_;
   }
@@ -34,10 +41,14 @@
   // Stub to throw AbstractMethodError
   static ByteArray* CreateAbstractMethodErrorStub(InstructionSet instruction_set);
 
+
   // Generate the trampoline that's invoked by unresolved direct methods
   static ByteArray* CreateResolutionStub(InstructionSet instruction_set,
                                          Runtime::TrampolineType type);
 
+  const CompiledMethod* GetCompiledMethod(const Method* method) const;
+  const CompiledInvokeStub* GetCompiledInvokeStub(const Method* method) const;
+
  private:
   // Attempt to resolve all type, methods, fields, and strings
   // referenced from code in the dex file following PathClassLoader
@@ -53,8 +64,8 @@
 
   void Compile(const ClassLoader* class_loader);
   void CompileDexFile(const ClassLoader* class_loader, const DexFile& dex_file);
-  void CompileClass(Class* klass);
-  void CompileMethod(Method* klass);
+  void CompileClass(const Class* klass);
+  void CompileMethod(const Method* method);
 
   // After compiling, walk all the DexCaches and set the code and
   // method pointers of CodeAndDirectMethods entries in the DexCaches.
@@ -64,6 +75,12 @@
   InstructionSet instruction_set_;
   JniCompiler jni_compiler_;
 
+  typedef std::tr1::unordered_map<const Method*, CompiledMethod*, ObjectIdentityHash> MethodTable;
+  MethodTable compiled_methods_;
+
+  typedef std::tr1::unordered_map<const Method*, CompiledInvokeStub*, ObjectIdentityHash> InvokeStubTable;
+  InvokeStubTable compiled_invoke_stubs_;
+
   bool verbose_;
 
   DISALLOW_COPY_AND_ASSIGN(Compiler);
diff --git a/src/compiler/Compiler.h b/src/compiler/Compiler.h
index f9e2478..28a689f 100644
--- a/src/compiler/Compiler.h
+++ b/src/compiler/Compiler.h
@@ -99,7 +99,9 @@
 void oatArchDump(void);
 bool oatStartup(void);
 void oatShutdown(void);
-bool oatCompileMethod(const Compiler& compiler, Method* method, OatInstructionSetType);
+CompiledMethod* oatCompileMethod(const Compiler& compiler,
+                                 const Method* method,
+                                 OatInstructionSetType);
 void oatDumpStats(void);
 void oatScanAllClassPointers(void (*callback)(void* ptr));
 void oatInitializeSSAConversion(struct CompilationUnit* cUnit);
diff --git a/src/compiler/Dalvik.h b/src/compiler/Dalvik.h
index 21b4297..422e20c0 100644
--- a/src/compiler/Dalvik.h
+++ b/src/compiler/Dalvik.h
@@ -60,6 +60,7 @@
 typedef art::Field Field;
 typedef art::JValue JValue;
 typedef art::Method Method;
+typedef art::CompiledMethod CompiledMethod;
 typedef art::Object Object;
 typedef art::String String;
 typedef art::Thread Thread;
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index 880341a..429d155 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -691,7 +691,7 @@
 /*
  * Compile a method.
  */
-bool oatCompileMethod(const Compiler& compiler, Method* method, art::InstructionSet insnSet)
+CompiledMethod* oatCompileMethod(const Compiler& compiler, const Method* method, art::InstructionSet insnSet)
 {
     if (compiler.IsVerbose()) {
         LOG(INFO) << "Compiling " << PrettyMethod(method) << "...";
@@ -894,17 +894,11 @@
         }
     }
 
-    art::ByteArray* managed_code =
-        art::ByteArray::Alloc(cUnit.codeBuffer.size() * sizeof(cUnit.codeBuffer[0]));
-    memcpy(managed_code->GetData(),
-           reinterpret_cast<const int8_t*>(&cUnit.codeBuffer[0]),
-           managed_code->GetLength());
-    art::IntArray* mapping_table =
-        art::IntArray::Alloc(cUnit.mappingTable.size());
-    DCHECK_EQ(mapping_table->GetClass()->GetComponentSize(), sizeof(cUnit.mappingTable[0]));
-    memcpy(mapping_table->GetData(),
-           reinterpret_cast<const int32_t*>(&cUnit.mappingTable[0]),
-           mapping_table->GetLength() * sizeof(cUnit.mappingTable[0]));
+    // Combine vmap tables - core regs, then fp regs - into vmapTable
+    std::vector<uint16_t> vmapTable;
+    for (size_t i = 0 ; i < cUnit.coreVmapTable.size(); i++) {
+        vmapTable.push_back(cUnit.coreVmapTable[i]);
+    }
     // Add a marker to take place of lr
     cUnit.coreVmapTable.push_back(INVALID_VREG);
     // Combine vmap tables - core regs, then fp regs
@@ -914,25 +908,25 @@
     DCHECK(cUnit.coreVmapTable.size() == (uint32_t)
         (__builtin_popcount(cUnit.coreSpillMask) +
          __builtin_popcount(cUnit.fpSpillMask)));
-    art::ShortArray* vmap_table =
-        art::ShortArray::Alloc(cUnit.coreVmapTable.size());
-    memcpy(vmap_table->GetData(),
-           reinterpret_cast<const int16_t*>(&cUnit.coreVmapTable[0]),
-           vmap_table->GetLength() * sizeof(cUnit.coreVmapTable[0]));
-    method->SetCodeArray(managed_code, art::kThumb2);
-    method->SetMappingTable(mapping_table);
-    method->SetVMapTable(vmap_table);
-    method->SetFrameSizeInBytes(cUnit.frameSize);
-    method->SetReturnPcOffsetInBytes(cUnit.frameSize - sizeof(intptr_t));
-    method->SetCoreSpillMask(cUnit.coreSpillMask);
-    method->SetFpSpillMask(cUnit.fpSpillMask);
+    vmapTable.push_back(-1);
+    for (size_t i = 0; i < cUnit.fpVmapTable.size(); i++) {
+        vmapTable.push_back(cUnit.fpVmapTable[i]);
+    }
+    CompiledMethod* result = new CompiledMethod(art::kThumb2,
+                                                cUnit.codeBuffer,
+                                                cUnit.frameSize,
+                                                cUnit.frameSize - sizeof(intptr_t),
+                                                cUnit.coreSpillMask,
+                                                cUnit.fpSpillMask,
+                                                cUnit.mappingTable,
+                                                cUnit.coreVmapTable);
+
     if (compiler.IsVerbose()) {
         LOG(INFO) << "Compiled " << PrettyMethod(method)
-                  << " code at " << reinterpret_cast<void*>(managed_code->GetData())
-                  << " (" << managed_code->GetLength() << " bytes)";
+                  << " (" << (cUnit.codeBuffer.size() * sizeof(cUnit.codeBuffer[0])) << " bytes)";
     }
 
-    return true;
+    return result;
 }
 
 void oatInit(const Compiler& compiler)
diff --git a/src/compiler_test.cc b/src/compiler_test.cc
index e951ade..f261406 100644
--- a/src/compiler_test.cc
+++ b/src/compiler_test.cc
@@ -18,34 +18,6 @@
 class CompilerTest : public CommonTest {
  protected:
 
-  void AssertStaticIntMethod(jint expected, const ClassLoader* class_loader,
-                             const char* class_name, const char* method, const char* signature,
-                             ...) {
-    EnsureCompiled(class_loader, class_name, method, signature, false);
-#if defined(__arm__)
-    va_list args;
-    va_start(args, signature);
-    jint result = env_->CallStaticIntMethodV(class_, mid_, args);
-    va_end(args);
-    LOG(INFO) << class_name << "." << method << "(...) result is " << result;
-    EXPECT_EQ(expected, result);
-#endif // __arm__
-  }
-
-  void AssertStaticLongMethod(jlong expected, const ClassLoader* class_loader,
-                              const char* class_name, const char* method, const char* signature,
-                              ...) {
-    EnsureCompiled(class_loader, class_name, method, signature, false);
-#if defined(__arm__)
-    va_list args;
-    va_start(args, signature);
-    jlong result = env_->CallStaticLongMethodV(class_, mid_, args);
-    va_end(args);
-    LOG(INFO) << class_name << "." << method << "(...) result is " << result;
-    EXPECT_EQ(expected, result);
-#endif // __arm__
-  }
-
   void CompileAll(const ClassLoader* class_loader) {
     compiler_->CompileAll(class_loader);
     MakeAllExecutable(class_loader);
@@ -83,27 +55,14 @@
       Class* c = class_linker->FindClass(descriptor, class_loader);
       CHECK(c != NULL);
       for (size_t i = 0; i < c->NumDirectMethods(); i++) {
-        MakeMethodExecutable(c->GetDirectMethod(i));
+        MakeExecutable(c->GetDirectMethod(i));
       }
       for (size_t i = 0; i < c->NumVirtualMethods(); i++) {
-        MakeMethodExecutable(c->GetVirtualMethod(i));
+        MakeExecutable(c->GetVirtualMethod(i));
       }
     }
   }
 
-  void MakeMethodExecutable(Method* m) {
-    if (m->GetCodeArray() != NULL) {
-      MakeExecutable(m->GetCodeArray());
-    } else {
-      LOG(WARNING) << "no code for " << PrettyMethod(m);
-    }
-    if (m->GetInvokeStubArray() != NULL) {
-      MakeExecutable(m->GetInvokeStubArray());
-    } else {
-      LOG(WARNING) << "no invoke stub for " << PrettyMethod(m);
-    }
-  }
-
   JNIEnv* env_;
   jclass class_;
   jmethodID mid_;
@@ -165,6 +124,8 @@
 }
 
 TEST_F(CompilerTest, AbstractMethodErrorStub) {
+  CompileDirectMethod(NULL, "java.lang.Object", "<init>", "()V");
+
   const ClassLoader* class_loader = LoadDex("AbstractMethod");
   ASSERT_TRUE(class_loader != NULL);
   EnsureCompiled(class_loader, "AbstractClass", "foo", "()V", true);
@@ -177,7 +138,7 @@
 
 #if defined(__arm__)
   Class* jlame = class_linker_->FindClass("Ljava/lang/AbstractMethodError;", class_loader);
-  // Force non-virtal call to AbstractClass foo, will throw AbstractMethodError exception.
+  // Force non-virtual call to AbstractClass foo, will throw AbstractMethodError exception.
   env_->CallNonvirtualVoidMethod(jobj_, class_, mid_);
   EXPECT_TRUE(Thread::Current()->IsExceptionPending());
   EXPECT_TRUE(Thread::Current()->GetException()->InstanceOf(jlame));
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 8d181d6..d5db436 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -258,7 +258,7 @@
     }
   }
 
-  if (!OatWriter::Create(oat_filename, class_loader)) {
+  if (!OatWriter::Create(oat_filename, class_loader, compiler)) {
     fprintf(stderr, "Failed to create oat file %s\n", oat_filename.c_str());
     return EXIT_FAILURE;
   }
diff --git a/src/dex_cache.h b/src/dex_cache.h
index 7ca6825..a9776b7 100644
--- a/src/dex_cache.h
+++ b/src/dex_cache.h
@@ -26,22 +26,17 @@
     return reinterpret_cast<Method*>(Get(MethodIndex(method_idx)));
   }
 
-  void SetResolvedDirectMethodTrampoline(uint32_t method_idx, ByteArray* code_array,
-                                         InstructionSet instruction_set) {
-    DCHECK(code_array != NULL);
+  void SetResolvedDirectMethodTrampoline(uint32_t method_idx, ByteArray* code_array) {
+    CHECK(code_array != NULL);
     int32_t code = reinterpret_cast<int32_t>(code_array->GetData());
-    if (instruction_set == kThumb2) {
-      // Set the low-order bit so a BLX will switch to Thumb mode
-      code = code | 0x1;
-    }
     Set(CodeIndex(method_idx), code);
     Set(MethodIndex(method_idx), method_idx);
   }
 
   void SetResolvedDirectMethod(uint32_t method_idx, Method* method) {
     CHECK(method != NULL);
-    CHECK(method->IsDirect());
-    // CHECK(method->GetCode() != NULL);  // TODO enable when all code is compiling
+    CHECK(method->IsDirect()) << PrettyMethod(method);
+    CHECK(method->GetCode() != NULL) << PrettyMethod(method);
     Set(CodeIndex(method_idx),   reinterpret_cast<int32_t>(method->GetCode()));
     Set(MethodIndex(method_idx), reinterpret_cast<int32_t>(method));
   }
@@ -213,12 +208,6 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(DexCache);
 };
 
-struct DexCacheHash {
-  size_t operator()(art::DexCache* const& obj) const {
-    return reinterpret_cast<size_t>(&obj);
-  }
-};
-
 }  // namespace art
 
 #endif  // ART_SRC_DEX_CACHE_H_
diff --git a/src/exception_test.cc b/src/exception_test.cc
index 49a5266..4662119 100644
--- a/src/exception_test.cc
+++ b/src/exception_test.cc
@@ -25,30 +25,34 @@
 
     dex_ = &Runtime::Current()->GetClassLinker()->FindDexFile(my_klass_->GetDexCache());
 
-    ByteArray* fake_code = ByteArray::Alloc(12);
-    ASSERT_TRUE(fake_code != NULL);
-    IntArray* fake_mapping_data = IntArray::Alloc(2);
-    ASSERT_TRUE(fake_mapping_data != NULL);
-    fake_mapping_data->Set(0, 3);  // offset 3
-    fake_mapping_data->Set(1, 3);  // maps to dex offset 3
+    for (size_t i = 0 ; i < 12; i++) {
+      fake_code_.push_back(0x70000000 | i);
+    }
+
+    fake_mapping_data_.push_back(2);  // first element is count of remaining elements
+    fake_mapping_data_.push_back(3);  // offset 3
+    fake_mapping_data_.push_back(3);  // maps to dex offset 3
 
     method_f_ = my_klass_->FindVirtualMethod("f", "()I");
     ASSERT_TRUE(method_f_ != NULL);
     method_f_->SetFrameSizeInBytes(kStackAlignment);
-    method_f_->SetReturnPcOffsetInBytes(kStackAlignment-kPointerSize);
-    method_f_->SetCodeArray(fake_code, kThumb2);
-    method_f_->SetMappingTable(fake_mapping_data);
+    method_f_->SetReturnPcOffsetInBytes(kStackAlignment - kPointerSize);
+    method_f_->SetCode(CompiledMethod::CodePointer(&fake_code_[0], kThumb2));
+    method_f_->SetMappingTable(&fake_mapping_data_[0]);
 
     method_g_ = my_klass_->FindVirtualMethod("g", "(I)V");
     ASSERT_TRUE(method_g_ != NULL);
     method_g_->SetFrameSizeInBytes(kStackAlignment);
-    method_g_->SetReturnPcOffsetInBytes(kStackAlignment-kPointerSize);
-    method_g_->SetCodeArray(fake_code, kThumb2);
-    method_g_->SetMappingTable(fake_mapping_data);
+    method_g_->SetReturnPcOffsetInBytes(kStackAlignment - kPointerSize);
+    method_g_->SetCode(CompiledMethod::CodePointer(&fake_code_[0], kThumb2));
+    method_g_->SetMappingTable(&fake_mapping_data_[0]);
   }
 
   const DexFile* dex_;
 
+  std::vector<uint8_t> fake_code_;
+  std::vector<uint32_t> fake_mapping_data_;
+
   Method* method_f_;
   Method* method_g_;
 
diff --git a/src/image_test.cc b/src/image_test.cc
index 903457f..2ef7489 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -18,7 +18,7 @@
 
 TEST_F(ImageTest, WriteRead) {
   ScratchFile tmp_oat;
-  bool success_oat = OatWriter::Create(tmp_oat.GetFilename(), NULL);
+  bool success_oat = OatWriter::Create(tmp_oat.GetFilename(), NULL, *compiler_.get());
   ASSERT_TRUE(success_oat);
 
   ImageWriter writer;
@@ -37,6 +37,7 @@
 
     ASSERT_EQ(1U, Heap::GetSpaces().size());
     Space* space = Heap::GetSpaces()[0];
+    ASSERT_FALSE(space->IsImageSpace());
     ASSERT_TRUE(space != NULL);
     ASSERT_GE(sizeof(image_header) + space->Size(), static_cast<size_t>(file->Length()));
   }
diff --git a/src/image_writer.cc b/src/image_writer.cc
index 8af9cf6..39f3e64 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -180,7 +180,7 @@
 
   // Note that image_top_ is left at end of used space
   oat_base_ = image_base_ +  RoundUp(image_top_, kPageSize);
-  byte* oat_limit = oat_base_ +  oat_file_->GetSize();
+  const byte* oat_limit = oat_base_ +  oat_file_->GetSize();
 
   // return to write header at start of image with future location of image_roots
   ImageHeader image_header(reinterpret_cast<uint32_t>(image_base_),
@@ -258,29 +258,42 @@
 void ImageWriter::FixupMethod(const Method* orig, Method* copy) {
   FixupInstanceFields(orig, copy);
 
-  // OatWriter clears the code_array_ after writing the code.
-  // It replaces the code_ with an offset value we now adjust to be a pointer.
-  DCHECK(copy->code_array_ == NULL)
-          << PrettyMethod(orig)
-          << " orig_code_array_=" << orig->GetCodeArray() << " orig_code_=" << orig->GetCode()
-          << " copy_code_array_=" << copy->code_array_ << " orig_code_=" << copy->code_
-          << " jni_stub=" << Runtime::Current()->GetJniStubArray()
-          << " ame_stub=" << Runtime::Current()->GetAbstractMethodErrorStubArray();
-  copy->invoke_stub_ = reinterpret_cast<Method::InvokeStub*>(FixupCode(copy->invoke_stub_array_, reinterpret_cast<void*>(orig->invoke_stub_)));
+  // OatWriter replaces the code_ and invoke_stub_ with offset values.
+  // Here we readjust to a pointer relative to oat_base_
+
+  // Every type of method can have an invoke stub
+  uint32_t invoke_stub_offset = orig->GetOatInvokeStubOffset();
+  const byte* invoke_stub = (invoke_stub_offset != 0) ? (oat_base_ + invoke_stub_offset) : 0;
+  copy->invoke_stub_ = reinterpret_cast<const Method::InvokeStub*>(invoke_stub);
+
+  if (orig->IsAbstract()) {
+    // Abstract methods are pointed to a stub that will throw AbstractMethodError if they are called
+    ByteArray* orig_ame_stub_array_ = Runtime::Current()->GetAbstractMethodErrorStubArray();
+    ByteArray* copy_ame_stub_array_ = down_cast<ByteArray*>(GetImageAddress(orig_ame_stub_array_));
+    copy->code_ = copy_ame_stub_array_->GetData();
+    return;
+  }
+
+  // Non-abstract methods typically have code
+  uint32_t code_offset = orig->GetOatCodeOffset();
+  const byte* code = (code_offset != 0) ? (oat_base_ + code_offset) : 0;
+  copy->code_ = code;
+
   if (orig->IsNative()) {
+    // The native method's pointer is directed to a stub to lookup via dlsym.
+    // Note this is not the code_ pointer, that is handled above.
     ByteArray* orig_jni_stub_array_ = Runtime::Current()->GetJniStubArray();
     ByteArray* copy_jni_stub_array_ = down_cast<ByteArray*>(GetImageAddress(orig_jni_stub_array_));
     copy->native_method_ = copy_jni_stub_array_->GetData();
-    copy->code_ = oat_base_ + orig->GetOatCodeOffset();
   } else {
-    DCHECK(copy->native_method_ == NULL) << copy->native_method_;
-    if (orig->IsAbstract()) {
-        ByteArray* orig_ame_stub_array_ = Runtime::Current()->GetAbstractMethodErrorStubArray();
-        ByteArray* copy_ame_stub_array_ = down_cast<ByteArray*>(GetImageAddress(orig_ame_stub_array_));
-        copy->code_ = copy_ame_stub_array_->GetData();
-    } else {
-        copy->code_ = oat_base_ + orig->GetOatCodeOffset();
-    }
+    // normal (non-abstract non-native) methods have mapping tables to relocate
+    uint32_t mapping_table_off = orig->GetOatMappingTableOffset();
+    const byte* mapping_table = (mapping_table_off != 0) ? (oat_base_ + mapping_table_off) : 0;
+    copy->mapping_table_ = reinterpret_cast<const uint32_t*>(mapping_table);
+
+    uint32_t vmap_table_offset = orig->GetOatVmapTableOffset();
+    const byte* vmap_table = (vmap_table_offset != 0) ? (oat_base_ + vmap_table_offset) : 0;
+    copy->vmap_table_ = reinterpret_cast<const uint16_t*>(vmap_table);
   }
 }
 
diff --git a/src/image_writer.h b/src/image_writer.h
index fda33fe..3c17538 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -116,10 +116,10 @@
   byte* image_base_;
 
   // Target oat base address for the pointers from the output image to its oat file
-  byte* oat_base_;
+  const byte* oat_base_;
 
   // DexCaches seen while scanning for fixing up CodeAndDirectMethods
-  typedef std::tr1::unordered_set<DexCache*, DexCacheHash> Set;
+  typedef std::tr1::unordered_set<DexCache*, ObjectIdentityHash> Set;
   Set dex_caches_;
 };
 
diff --git a/src/jni_compiler.cc b/src/jni_compiler.cc
index 83be88a..ffcbc11 100644
--- a/src/jni_compiler.cc
+++ b/src/jni_compiler.cc
@@ -7,11 +7,12 @@
 
 #include "assembler.h"
 #include "calling_convention.h"
+#include "compiled_method.h"
 #include "constants.h"
 #include "jni_internal.h"
+#include "logging.h"
 #include "macros.h"
 #include "managed_register.h"
-#include "logging.h"
 #include "thread.h"
 #include "UniquePtr.h"
 
@@ -38,12 +39,12 @@
   }
 }
 
-JniCompiler::JniCompiler(InstructionSet insns) {
-  if (insns == kThumb2) {
+JniCompiler::JniCompiler(InstructionSet instruction_set) {
+  if (instruction_set == kThumb2) {
     // currently only ARM code generation is supported
     instruction_set_ = kArm;
   } else {
-    instruction_set_ = insns;
+    instruction_set_ = instruction_set;
   }
 }
 
@@ -54,7 +55,7 @@
 //   registers, a reference to the method object is supplied as part of this
 //   convention.
 //
-void JniCompiler::Compile(Method* native_method) {
+CompiledMethod* JniCompiler::Compile(const Method* native_method) {
   CHECK(native_method->IsNative());
 
   // Calling conventions used to iterate over parameters to method
@@ -426,15 +427,15 @@
   // 17. Finalize code generation
   __ EmitSlowPaths();
   size_t cs = __ CodeSize();
-  ByteArray* managed_code = ByteArray::Alloc(cs);
-  CHECK(managed_code != NULL);
-  MemoryRegion code(managed_code->GetData(), managed_code->GetLength());
+  std::vector<uint8_t> managed_code(cs);
+  MemoryRegion code(&managed_code[0], managed_code.size());
   __ FinalizeInstructions(code);
-  native_method->SetCodeArray(managed_code, instruction_set_);
-  native_method->SetFrameSizeInBytes(frame_size);
-  native_method->SetReturnPcOffsetInBytes(jni_conv->ReturnPcOffset());
-  native_method->SetCoreSpillMask(jni_conv->CoreSpillMask());
-  native_method->SetFpSpillMask(jni_conv->FpSpillMask());
+  return new CompiledMethod(instruction_set_,
+                            managed_code,
+                            frame_size,
+                            jni_conv->ReturnPcOffset(),
+                            jni_conv->CoreSpillMask(),
+                            jni_conv->FpSpillMask());
 #undef __
 }
 
diff --git a/src/jni_compiler.h b/src/jni_compiler.h
index 086d96e..a6d5602 100644
--- a/src/jni_compiler.h
+++ b/src/jni_compiler.h
@@ -3,6 +3,7 @@
 #ifndef ART_SRC_JNI_COMPILER_H_
 #define ART_SRC_JNI_COMPILER_H_
 
+#include "compiled_method.h"
 #include "constants.h"
 #include "macros.h"
 #include "object.h"
@@ -10,6 +11,7 @@
 namespace art {
 
 class Assembler;
+class Compiler;
 class JniCallingConvention;
 class ManagedRegister;
 class ManagedRuntimeCallingConvention;
@@ -20,10 +22,10 @@
 // TODO: move the responsibility of managing memory to somewhere else
 class JniCompiler {
  public:
-  explicit JniCompiler(InstructionSet insns);
+  explicit JniCompiler(InstructionSet instruction_set);
   ~JniCompiler();
 
-  void Compile(Method* method);
+  CompiledMethod* Compile(const Method* method);
 
   // Stub to perform native method symbol lookup via dlsym
   // TODO: remove from JniCompiler
diff --git a/src/jni_internal_arm.cc b/src/jni_internal_arm.cc
index 8ba5717..ba13de7 100644
--- a/src/jni_internal_arm.cc
+++ b/src/jni_internal_arm.cc
@@ -5,6 +5,7 @@
 #include <algorithm>
 
 #include "assembler.h"
+#include "compiled_method.h"
 #include "object.h"
 
 namespace art {
@@ -27,7 +28,7 @@
 // register and transfer arguments from the array into register and on
 // the stack, if needed.  On return, the thread register must be
 // shuffled and the return value must be store into the result JValue.
-void ArmCreateInvokeStub(Method* method) {
+CompiledInvokeStub* ArmCreateInvokeStub(const Method* method) {
   UniquePtr<ArmAssembler> assembler(
       down_cast<ArmAssembler*>(Assembler::Create(kArm)));
 #define __ assembler->
@@ -118,11 +119,10 @@
   // Pop R4, R9 and the LR into PC
   __ PopList(save | (1 << PC));
   // TODO: store native_entry in the stub table
-  ByteArray* code = ByteArray::Alloc(assembler->CodeSize());
-  MemoryRegion region(code->GetData(), code->GetLength());
+  std::vector<uint8_t> code(assembler->CodeSize());
+  MemoryRegion region(&code[0], code.size());
   assembler->FinalizeInstructions(region);
-  method->SetInvokeStub(code);
-  CHECK(method->GetInvokeStub() != NULL);
+  return new CompiledInvokeStub(code);
 #undef __
 }
 
diff --git a/src/jni_internal_x86.cc b/src/jni_internal_x86.cc
index 7128c6e..891971d 100644
--- a/src/jni_internal_x86.cc
+++ b/src/jni_internal_x86.cc
@@ -3,6 +3,7 @@
 #include "jni_internal.h"
 
 #include "assembler.h"
+#include "compiled_method.h"
 #include "object.h"
 
 namespace art {
@@ -24,7 +25,7 @@
 // "running" state the remaining responsibilities of this routine are
 // to save the native registers and set up the managed registers. On
 // return, the return value must be store into the result JValue.
-void X86CreateInvokeStub(Method* method) {
+CompiledInvokeStub* X86CreateInvokeStub(const Method* method) {
   UniquePtr<X86Assembler> assembler(
       down_cast<X86Assembler*>(Assembler::Create(kX86)));
 #define __ assembler->
@@ -79,11 +80,10 @@
   }
   __ ret();
   // TODO: store native_entry in the stub table
-  ByteArray* code = ByteArray::Alloc(assembler->CodeSize());
-  MemoryRegion region(code->GetData(), code->GetLength());
+  std::vector<uint8_t> code(assembler->CodeSize());
+  MemoryRegion region(&code[0], code.size());
   assembler->FinalizeInstructions(region);
-  method->SetInvokeStub(code);
-  CHECK(method->GetInvokeStub() != NULL);
+  return new CompiledInvokeStub(code);
 #undef __
 }
 
diff --git a/src/oat.cc b/src/oat.cc
index 191f26f..8bf8299 100644
--- a/src/oat.cc
+++ b/src/oat.cc
@@ -65,4 +65,33 @@
   UpdateChecksum(&executable_offset_, sizeof(executable_offset));
 }
 
+OatMethodOffsets::OatMethodOffsets()
+ : code_offset_(0),
+   frame_size_in_bytes_(0),
+   return_pc_offset_in_bytes_(0),
+   core_spill_mask_(0),
+   fp_spill_mask_(0),
+   mapping_table_offset_(0),
+   vmap_table_offset_(0),
+   invoke_stub_offset_(0) {}
+
+OatMethodOffsets::OatMethodOffsets(uint32_t code_offset,
+                                   uint32_t frame_size_in_bytes,
+                                   uint32_t return_pc_offset_in_bytes,
+                                   uint32_t core_spill_mask,
+                                   uint32_t fp_spill_mask,
+                                   uint32_t mapping_table_offset,
+                                   uint32_t vmap_table_offset,
+                                   uint32_t invoke_stub_offset)
+ : code_offset_(code_offset),
+   frame_size_in_bytes_(frame_size_in_bytes),
+   return_pc_offset_in_bytes_(return_pc_offset_in_bytes),
+   core_spill_mask_(core_spill_mask),
+   fp_spill_mask_(fp_spill_mask),
+   mapping_table_offset_(mapping_table_offset),
+   vmap_table_offset_(vmap_table_offset),
+   invoke_stub_offset_(invoke_stub_offset) {}
+
+OatMethodOffsets::~OatMethodOffsets() {}
+
 }  // namespace art
diff --git a/src/oat.h b/src/oat.h
index ca3e9e0..ff50599 100644
--- a/src/oat.h
+++ b/src/oat.h
@@ -36,6 +36,29 @@
   DISALLOW_COPY_AND_ASSIGN(OatHeader);
 };
 
+class PACKED OatMethodOffsets {
+ public:
+  OatMethodOffsets();
+  OatMethodOffsets(uint32_t code_offset,
+                   uint32_t frame_size_in_bytes,
+                   uint32_t return_pc_offset_in_bytes,
+                   uint32_t core_spill_mask,
+                   uint32_t fp_spill_mask,
+                   uint32_t mapping_table_offset,
+                   uint32_t vmap_table_offset,
+                   uint32_t invoke_stub_offset);
+  ~OatMethodOffsets();
+
+  uint32_t code_offset_;
+  uint32_t frame_size_in_bytes_;
+  uint32_t return_pc_offset_in_bytes_;
+  uint32_t core_spill_mask_;
+  uint32_t fp_spill_mask_;
+  uint32_t mapping_table_offset_;
+  uint32_t vmap_table_offset_;
+  uint32_t invoke_stub_offset_;
+};
+
 }  // namespace art
 
 #endif  // ART_SRC_OAT_H_
diff --git a/src/oat_file.cc b/src/oat_file.cc
index 15221a6..95ef64c 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -146,22 +146,56 @@
   uint32_t methods_offset = classes_pointer_[class_def_index];
   const byte* methods_pointer = oat_file_->GetBase() + methods_offset;
   CHECK_LT(methods_pointer, oat_file_->GetLimit());
-  return OatClass(oat_file_, reinterpret_cast<const uint32_t*>(methods_pointer));
+  return OatClass(oat_file_, reinterpret_cast<const OatMethodOffsets*>(methods_pointer));
 }
 
-OatFile::OatClass::OatClass(const OatFile* oat_file, const uint32_t* methods_pointer)
+OatFile::OatClass::OatClass(const OatFile* oat_file, const OatMethodOffsets* methods_pointer)
     : oat_file_(oat_file), methods_pointer_(methods_pointer) {}
 
 OatFile::OatClass::~OatClass() {}
 
-const void* OatFile::OatClass::GetMethodCode(uint32_t method_index) const {
-  uint32_t code_offset = methods_pointer_[method_index];
-  if (code_offset == 0) {
-    return NULL;
-  }
-  const void* code_pointer = reinterpret_cast<const void*>(oat_file_->GetBase() + code_offset);
-  CHECK_LT(code_pointer, oat_file_->GetLimit());
-  return code_pointer;
+const OatFile::OatMethod OatFile::OatClass::GetOatMethod(uint32_t method_index) const {
+  const OatMethodOffsets& oat_method_offsets = methods_pointer_[method_index];
+  return OatMethod(
+      GetOatPointer<const void*>(oat_method_offsets.code_offset_),
+      oat_method_offsets.frame_size_in_bytes_,
+      oat_method_offsets.return_pc_offset_in_bytes_,
+      oat_method_offsets.core_spill_mask_,
+      oat_method_offsets.fp_spill_mask_,
+      GetOatPointer<const uint32_t*>(oat_method_offsets.mapping_table_offset_),
+      GetOatPointer<const uint16_t*>(oat_method_offsets.vmap_table_offset_),
+      GetOatPointer<const Method::InvokeStub*>(oat_method_offsets.invoke_stub_offset_));
+}
+
+OatFile::OatMethod::OatMethod(const void* code,
+                              const size_t frame_size_in_bytes,
+                              const size_t return_pc_offset_in_bytes,
+                              const uint32_t core_spill_mask,
+                              const uint32_t fp_spill_mask,
+                              const uint32_t* mapping_table,
+                              const uint16_t* vmap_table,
+                              const Method::InvokeStub* invoke_stub) :
+  code_(code),
+  frame_size_in_bytes_(frame_size_in_bytes),
+  return_pc_offset_in_bytes_(return_pc_offset_in_bytes),
+  core_spill_mask_(core_spill_mask),
+  fp_spill_mask_(fp_spill_mask),
+  mapping_table_(mapping_table),
+  vmap_table_(vmap_table),
+  invoke_stub_(invoke_stub) {}
+
+OatFile::OatMethod::~OatMethod() {}
+
+void OatFile::OatMethod::LinkMethod(Method* method) {
+  CHECK(method != NULL);
+  method->SetCode(code_);
+  method->SetFrameSizeInBytes(frame_size_in_bytes_);
+  method->SetReturnPcOffsetInBytes(return_pc_offset_in_bytes_);
+  method->SetCoreSpillMask(core_spill_mask_);
+  method->SetFpSpillMask(fp_spill_mask_);
+  method->SetMappingTable(mapping_table_);
+  method->SetVmapTable(vmap_table_);
+  method->SetInvokeStub(invoke_stub_);
 }
 
 }  // namespace art
diff --git a/src/oat_file.h b/src/oat_file.h
index 6027dda..0472c16 100644
--- a/src/oat_file.h
+++ b/src/oat_file.h
@@ -5,9 +5,11 @@
 
 #include <vector>
 
+#include "constants.h"
 #include "dex_file.h"
 #include "mem_map.h"
 #include "oat.h"
+#include "object.h"
 
 namespace art {
 
@@ -30,20 +32,57 @@
 
   class OatDexFile;
 
+  class OatMethod {
+   public:
+    // Create an OatMethod backed by an OatFile
+    OatMethod(const void* code,
+              const size_t frame_size_in_bytes,
+              const size_t return_pc_offset_in_bytes,
+              const uint32_t core_spill_mask,
+              const uint32_t fp_spill_mask,
+              const uint32_t* mapping_table,
+              const uint16_t* vmap_table,
+              const Method::InvokeStub* invoke_stub);
+
+    ~OatMethod();
+
+    // Link Method using the contents of this OatMethod
+    void LinkMethod(Method* method);
+
+    const void* code_;
+    size_t frame_size_in_bytes_;
+    size_t return_pc_offset_in_bytes_;
+    uint32_t core_spill_mask_;
+    uint32_t fp_spill_mask_;
+    const uint32_t* mapping_table_;
+    const uint16_t* vmap_table_;
+    const Method::InvokeStub* invoke_stub_;
+  };
+
   class OatClass {
    public:
-    // get the code for the method based on its index into the class
+    // get the OatMethod entry based on its index into the class
     // defintion. direct methods come first, followed by virtual
     // methods. note that runtime created methods such as miranda
     // methods are not included.
-    const void* GetMethodCode(uint32_t method_index) const;
+    const OatMethod GetOatMethod(uint32_t method_idx) const;
     ~OatClass();
 
    private:
-    OatClass(const OatFile* oat_file, const uint32_t* methods_pointer);
+    OatClass(const OatFile* oat_file, const OatMethodOffsets* methods_pointer);
+
+    template<class T>
+    T GetOatPointer(uint32_t offset) const {
+      if (offset == 0) {
+        return NULL;
+      }
+      T pointer = reinterpret_cast<T>(oat_file_->GetBase() + offset);
+      CHECK_LT(pointer, reinterpret_cast<T>(oat_file_->GetLimit()));
+      return pointer;
+    }
 
     const OatFile* oat_file_;
-    const uint32_t* methods_pointer_;
+    const OatMethodOffsets* methods_pointer_;
 
     friend class OatDexFile;
   };
diff --git a/src/oat_test.cc b/src/oat_test.cc
index c3d012e..3137728 100644
--- a/src/oat_test.cc
+++ b/src/oat_test.cc
@@ -14,11 +14,12 @@
 
   const ClassLoader* class_loader = NULL;
   if (compile) {
+    compiler_.reset(new Compiler(kThumb2));
     compiler_->CompileAll(class_loader);
   }
 
   ScratchFile tmp;
-  bool success = OatWriter::Create(tmp.GetFilename(), class_loader);
+  bool success = OatWriter::Create(tmp.GetFilename(), class_loader, *compiler_.get());
   ASSERT_TRUE(success);
 
   if (compile) {  // OatWriter strips the code, regenerate to compare
@@ -29,10 +30,7 @@
   const OatHeader& oat_header = oat_file->GetOatHeader();
   ASSERT_EQ(1U, oat_header.GetDexFileCount());
 
-  const Runtime* runtime = Runtime::Current();
-  ClassLinker* class_linker = runtime->GetClassLinker();
-  ByteArray* jni_stub_array = runtime->GetJniStubArray();
-  ByteArray* ame_stub_array = runtime->GetAbstractMethodErrorStubArray();
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
 
   const DexFile& dex_file = *java_lang_dex_file_.get();
   const OatFile::OatDexFile& oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
@@ -50,27 +48,57 @@
     size_t method_index = 0;
     for (size_t i = 0; i < klass->NumDirectMethods(); i++, method_index++) {
       Method* method = klass->GetDirectMethod(i);
-      const void* oat_code = oat_class.GetMethodCode(method_index);
-      uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(oat_code), 2);
-      oat_code = reinterpret_cast<const void*>(oat_code_aligned);
-      const ByteArray* code_array = method->GetCodeArray();
-      if (code_array == NULL || code_array == jni_stub_array || code_array == ame_stub_array) {
-        ASSERT_TRUE(oat_code == NULL);
+      const OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index);
+      const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method);
+
+      if (compiled_method == NULL) {
+        EXPECT_TRUE(oat_method.code_ == NULL) << PrettyMethod(method) << " " << oat_method.code_;
+        EXPECT_EQ(oat_method.frame_size_in_bytes_, static_cast<uint32_t>(kStackAlignment));
+        EXPECT_EQ(oat_method.return_pc_offset_in_bytes_, 0U);
+        EXPECT_EQ(oat_method.core_spill_mask_, 0U);
+        EXPECT_EQ(oat_method.fp_spill_mask_, 0U);
       } else {
-        ASSERT_EQ(0, memcmp(oat_code, code_array->GetData(), code_array->GetLength()));
+        const void* oat_code = oat_method.code_;
+        uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(oat_code), 2);
+        oat_code = reinterpret_cast<const void*>(oat_code_aligned);
+
+        const std::vector<uint8_t>& code = compiled_method->GetCode();
+        size_t code_size = code.size() * sizeof(code[0]);
+        EXPECT_EQ(0, memcmp(oat_code, &code[0], code_size))
+            << PrettyMethod(method) << " " << code_size;
+        CHECK_EQ(0, memcmp(oat_code, &code[0], code_size));
+        EXPECT_EQ(oat_method.frame_size_in_bytes_, compiled_method->GetFrameSizeInBytes());
+        EXPECT_EQ(oat_method.return_pc_offset_in_bytes_, compiled_method->GetReturnPcOffsetInBytes());
+        EXPECT_EQ(oat_method.core_spill_mask_, compiled_method->GetCoreSpillMask());
+        EXPECT_EQ(oat_method.fp_spill_mask_, compiled_method->GetFpSpillMask());
       }
     }
     for (size_t i = 0; i < num_virtual_methods; i++, method_index++) {
       Method* method = klass->GetVirtualMethod(i);
-      const void* oat_code = oat_class.GetMethodCode(method_index);
-      uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(oat_code), 2);
-      oat_code = reinterpret_cast<const void*>(oat_code_aligned);
-      const ByteArray* code_array = method->GetCodeArray();
-      if (code_array == NULL || code_array == jni_stub_array || code_array == ame_stub_array) {
-        ASSERT_TRUE(oat_code == NULL);
+      const OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index);
+      const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method);
+
+      if (compiled_method == NULL) {
+        EXPECT_TRUE(oat_method.code_ == NULL) << PrettyMethod(method) << " " << oat_method.code_;
+        EXPECT_EQ(oat_method.frame_size_in_bytes_, static_cast<uint32_t>(kStackAlignment));
+        EXPECT_EQ(oat_method.return_pc_offset_in_bytes_, 0U);
+        EXPECT_EQ(oat_method.core_spill_mask_, 0U);
+        EXPECT_EQ(oat_method.fp_spill_mask_, 0U);
       } else {
-        ASSERT_TRUE(oat_code != NULL);
-        ASSERT_EQ(0, memcmp(oat_code, code_array->GetData(), code_array->GetLength()));
+        const void* oat_code = oat_method.code_;
+        EXPECT_TRUE(oat_code != NULL) << PrettyMethod(method);
+        uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(oat_code), 2);
+        oat_code = reinterpret_cast<const void*>(oat_code_aligned);
+
+        const std::vector<uint8_t>& code = compiled_method->GetCode();
+        size_t code_size = code.size() * sizeof(code[0]);
+        EXPECT_EQ(0, memcmp(oat_code, &code[0], code_size))
+            << PrettyMethod(method) << " " << code_size;
+        CHECK_EQ(0, memcmp(oat_code, &code[0], code_size));
+        EXPECT_EQ(oat_method.frame_size_in_bytes_, compiled_method->GetFrameSizeInBytes());
+        EXPECT_EQ(oat_method.return_pc_offset_in_bytes_, compiled_method->GetReturnPcOffsetInBytes());
+        EXPECT_EQ(oat_method.core_spill_mask_, compiled_method->GetCoreSpillMask());
+        EXPECT_EQ(oat_method.fp_spill_mask_, compiled_method->GetFpSpillMask());
       }
     }
   }
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index b8232d9..0722520 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -10,13 +10,18 @@
 
 namespace art {
 
-bool OatWriter::Create(const std::string& filename, const ClassLoader* class_loader) {
+bool OatWriter::Create(const std::string& filename,
+                       const ClassLoader* class_loader,
+                       const Compiler& compiler) {
   const std::vector<const DexFile*>& dex_files = ClassLoader::GetClassPath(class_loader);
-  OatWriter oat_writer(dex_files, class_loader);
+  OatWriter oat_writer(dex_files, class_loader, compiler);
   return oat_writer.Write(filename);
 }
 
-OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files, const ClassLoader* class_loader) {
+OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
+                     const ClassLoader* class_loader,
+                     const Compiler& compiler) {
+  compiler_ = &compiler;
   class_loader_ = class_loader;
   dex_files_ = &dex_files;
 
@@ -141,7 +146,6 @@
   CHECK_EQ(klass->GetClassLoader(), class_loader_);
   CHECK_EQ(oat_methods_[oat_class_index]->method_offsets_.size(),
            klass->NumDirectMethods() + num_virtual_methods);
-  // Note that we leave the offset to the code in Method::code_
   size_t class_def_method_index = 0;
   for (size_t i = 0; i < klass->NumDirectMethods(); i++, class_def_method_index++) {
     Method* method = klass->GetDirectMethod(i);
@@ -161,27 +165,99 @@
                                     size_t oat_class_index,
                                     size_t class_def_method_index,
                                     Method* method) {
-  Runtime* runtime = Runtime::Current();
-  ByteArray* jni_stub_array = runtime->GetJniStubArray();
-  ByteArray* ame_stub_array = runtime->GetAbstractMethodErrorStubArray();
+  // derived from CompiledMethod if available
+  uint32_t code_offset = 0;
+  uint32_t frame_size_in_bytes = kStackAlignment;
+  uint32_t return_pc_offset_in_bytes = 0;
+  uint32_t core_spill_mask = 0;
+  uint32_t fp_spill_mask = 0;
+  uint32_t mapping_table_offset = 0;
+  uint32_t vmap_table_offset = 0;
+  // derived from CompiledInvokeStub if available
+  uint32_t invoke_stub_offset = 0;
 
-  const ByteArray* code_array = method->GetCodeArray();
-  if (code_array == NULL || code_array == jni_stub_array || code_array == ame_stub_array) {
-    oat_methods_[oat_class_index]->method_offsets_[class_def_method_index] = 0;
-    method->SetOatCodeOffset(0);
-  } else {
-    offset = RoundUp(offset, kArmAlignment);
-    uint32_t thumb_offset = (reinterpret_cast<const int8_t*>(method->GetCode())
-                             - code_array->GetData());
-    uint32_t code_offset = offset + thumb_offset;
-    oat_methods_[oat_class_index]->method_offsets_[class_def_method_index] = code_offset;
-    method->SetOatCodeOffset(code_offset);
-    offset += code_array->GetLength();
-    oat_header_->UpdateChecksum(code_array->GetData(), code_array->GetLength());
+  const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method);
+  if (compiled_method != NULL) {
+
+    offset = compiled_method->AlignCode(offset);
+    DCHECK(IsAligned(offset, kArmAlignment)) << std::hex << offset;
+    const std::vector<uint8_t>& code = compiled_method->GetCode();
+    size_t code_size = code.size() * sizeof(code[0]);
+    uint32_t thumb_offset = compiled_method->CodeDelta();
+    code_offset = (code_size == 0) ? 0 : offset + thumb_offset;
+    offset += code_size;
+    oat_header_->UpdateChecksum(&code[0], code_size);
+
+    frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
+    return_pc_offset_in_bytes = compiled_method->GetReturnPcOffsetInBytes();
+    core_spill_mask = compiled_method->GetCoreSpillMask();
+    fp_spill_mask = compiled_method->GetFpSpillMask();
   }
+
+  offset += sizeof(frame_size_in_bytes);
+  oat_header_->UpdateChecksum(&frame_size_in_bytes, sizeof(frame_size_in_bytes));
+
+  offset += sizeof(return_pc_offset_in_bytes);
+  oat_header_->UpdateChecksum(&return_pc_offset_in_bytes, sizeof(return_pc_offset_in_bytes));
+
+  offset += sizeof(core_spill_mask);
+  oat_header_->UpdateChecksum(&core_spill_mask, sizeof(core_spill_mask));
+
+  offset += sizeof(fp_spill_mask);
+  oat_header_->UpdateChecksum(&fp_spill_mask, sizeof(fp_spill_mask));
+
+  if (compiled_method != NULL) {
+
+    const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
+    size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
+    mapping_table_offset = (mapping_table_size == 0) ? 0 : offset;
+    offset += mapping_table_size;
+    oat_header_->UpdateChecksum(&mapping_table[0], mapping_table_size);
+
+    const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
+    size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
+    vmap_table_offset = (vmap_table_size == 0) ? 0 : offset;
+    offset += vmap_table_size;
+    oat_header_->UpdateChecksum(&vmap_table[0], vmap_table_size);
+  }
+
+  const CompiledInvokeStub* compiled_invoke_stub = compiler_->GetCompiledInvokeStub(method);
+  if (compiled_invoke_stub != NULL) {
+    offset = CompiledMethod::AlignCode(offset, compiler_->GetInstructionSet());
+    DCHECK(IsAligned(offset, kArmAlignment)) << std::hex << offset;
+    const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
+    size_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
+    invoke_stub_offset = (invoke_stub_size == 0) ? 0 : offset;
+    offset += invoke_stub_size;
+    oat_header_->UpdateChecksum(&invoke_stub[0], invoke_stub_size);
+  }
+
+  oat_methods_[oat_class_index]->method_offsets_[class_def_method_index]
+      = OatMethodOffsets(code_offset,
+                         frame_size_in_bytes,
+                         return_pc_offset_in_bytes,
+                         core_spill_mask,
+                         fp_spill_mask,
+                         mapping_table_offset,
+                         vmap_table_offset,
+                         invoke_stub_offset);
+
+  // Note that we leave the offset and values back in the Method where ImageWriter will find them
+  method->SetOatCodeOffset(code_offset);
+  method->SetFrameSizeInBytes(frame_size_in_bytes);
+  method->SetReturnPcOffsetInBytes(return_pc_offset_in_bytes);
+  method->SetCoreSpillMask(core_spill_mask);
+  method->SetFpSpillMask(fp_spill_mask);
+  method->SetOatMappingTableOffset(mapping_table_offset);
+  method->SetOatVmapTableOffset(vmap_table_offset);
+  method->SetOatInvokeStubOffset(invoke_stub_offset);
+
   return offset;
 }
 
+#define DCHECK_CODE_OFFSET() \
+  DCHECK_EQ(static_cast<off_t>(code_offset), lseek(file->Fd(), 0, SEEK_CUR))
+
 bool OatWriter::Write(const std::string& filename) {
 
   UniquePtr<File> file(OS::OpenFile(filename.c_str(), true));
@@ -240,9 +316,11 @@
   uint32_t code_offset = oat_header_->GetExecutableOffset();
   off_t new_offset = lseek(file->Fd(), executable_offset_padding_length_, SEEK_CUR);
   if (static_cast<uint32_t>(new_offset) != code_offset) {
-    PLOG(ERROR) << "Failed to seek to oat code section";
+    PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
+                << " Expected: " << code_offset;
     return 0;
   }
+  DCHECK_CODE_OFFSET();
   return code_offset;
 }
 
@@ -277,14 +355,11 @@
                                     size_t code_offset,
                                     const DexFile& dex_file,
                                     const DexFile::ClassDef& class_def) {
-  const Runtime* runtime = Runtime::Current();
-  ClassLinker* class_linker = runtime->GetClassLinker();
-  ByteArray* ame_stub_array = runtime->GetAbstractMethodErrorStubArray();
-
   const byte* class_data = dex_file.GetClassData(class_def);
   DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data);
   size_t num_virtual_methods = header.virtual_methods_size_;
   const char* descriptor = dex_file.GetClassDescriptor(class_def);
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   Class* klass = class_linker->FindClass(descriptor, class_loader_);
 
   // TODO: deduplicate code arrays
@@ -306,11 +381,7 @@
   }
   for (size_t i = num_virtual_methods; i < klass->NumVirtualMethods(); i++) {
     Method* method = klass->GetVirtualMethod(i);
-    const ByteArray* code_array = method->GetCodeArray();
-    CHECK(code_array == NULL  // if compiler not run
-          || code_array == ame_stub_array)  // otherwise
-            << PrettyMethod(method) << " " << code_array;
-    method->SetCodeArray(NULL, kNone);
+    CHECK(compiler_->GetCompiledMethod(method) == NULL) << PrettyMethod(method);
   }
   return code_offset;
 }
@@ -318,32 +389,110 @@
 size_t OatWriter::WriteCodeMethod(File* file,
                                   size_t code_offset,
                                   Method* method) {
-  const Runtime* runtime = Runtime::Current();
-  ByteArray* jni_stub_array = runtime->GetJniStubArray();
-  ByteArray* ame_stub_array = runtime->GetAbstractMethodErrorStubArray();
-
-  const ByteArray* code_array = method->GetCodeArray();
-  if (code_array != NULL && code_array != jni_stub_array && code_array != ame_stub_array) {
-    uint32_t aligned_code_offset = RoundUp(code_offset, kArmAlignment);
+  const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method);
+  if (compiled_method != NULL) {
+    uint32_t aligned_code_offset = compiled_method->AlignCode(code_offset);
     uint32_t aligned_code_delta = aligned_code_offset - code_offset;
     if (aligned_code_delta != 0) {
       off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
       if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
-        PLOG(ERROR) << "Failed to seek to align oat code";
+        PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
+                    << " Expected: " << aligned_code_offset;
         return false;
       }
       code_offset += aligned_code_delta;
+      DCHECK_CODE_OFFSET();
     }
-    if (!file->WriteFully(code_array->GetData(), code_array->GetLength())) {
+    DCHECK(IsAligned(code_offset, kArmAlignment)) << std::hex << code_offset;
+    const std::vector<uint8_t>& code = compiled_method->GetCode();
+    size_t code_size = code.size() * sizeof(code[0]);
+    DCHECK((code_size == 0 && method->GetOatCodeOffset() == 0)
+           || code_offset + compiled_method->CodeDelta() == method->GetOatCodeOffset());
+    if (!file->WriteFully(&code[0], code_size)) {
       PLOG(ERROR) << "Failed to write method code for " << PrettyMethod(method);
       return false;
     }
-    code_offset += code_array->GetLength();
+    code_offset += code_size;
+    DCHECK_CODE_OFFSET();
   }
-  // preserve code offset around code clearing
-  uint32_t offset = method->GetOatCodeOffset();
-  method->SetCodeArray(NULL, kNone);
-  method->SetOatCodeOffset(offset);
+
+  uint32_t frame_size_in_bytes = method->GetFrameSizeInBytes();
+  uint32_t return_pc_offset_in_bytes = method->GetReturnPcOffsetInBytes();
+  uint32_t core_spill_mask = method->GetCoreSpillMask();
+  uint32_t fp_spill_mask = method->GetFpSpillMask();
+  if (!file->WriteFully(&frame_size_in_bytes, sizeof(frame_size_in_bytes))) {
+    PLOG(ERROR) << "Failed to write method frame size for " << PrettyMethod(method);
+    return false;
+  }
+  code_offset += sizeof(frame_size_in_bytes);
+  if (!file->WriteFully(&return_pc_offset_in_bytes, sizeof(return_pc_offset_in_bytes))) {
+    PLOG(ERROR) << "Failed to write method return pc offset for " << PrettyMethod(method);
+    return false;
+  }
+  code_offset += sizeof(return_pc_offset_in_bytes);
+  if (!file->WriteFully(&core_spill_mask, sizeof(core_spill_mask))) {
+    PLOG(ERROR) << "Failed to write method core spill mask for " << PrettyMethod(method);
+    return false;
+  }
+  code_offset += sizeof(core_spill_mask);
+  if (!file->WriteFully(&fp_spill_mask, sizeof(fp_spill_mask))) {
+    PLOG(ERROR) << "Failed to write method fp spill mask for " << PrettyMethod(method);
+    return false;
+  }
+  code_offset += sizeof(fp_spill_mask);
+
+  if (compiled_method != NULL) {
+    const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
+    size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
+    DCHECK((mapping_table_size == 0 && method->GetOatMappingTableOffset() == 0)
+           || code_offset == method->GetOatMappingTableOffset());
+    if (!file->WriteFully(&mapping_table[0], mapping_table_size)) {
+      PLOG(ERROR) << "Failed to write mapping table for " << PrettyMethod(method);
+      return false;
+    }
+    code_offset += mapping_table_size;
+    DCHECK_CODE_OFFSET();
+
+    const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
+    size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
+    DCHECK((vmap_table_size == 0 && method->GetOatVmapTableOffset() == 0)
+           || code_offset == method->GetOatVmapTableOffset());
+    if (!file->WriteFully(&vmap_table[0], vmap_table_size)) {
+      PLOG(ERROR) << "Failed to write vmap table for " << PrettyMethod(method);
+      return false;
+    }
+    code_offset += vmap_table_size;
+    DCHECK_CODE_OFFSET();
+  }
+
+  const CompiledInvokeStub* compiled_invoke_stub = compiler_->GetCompiledInvokeStub(method);
+  if (compiled_invoke_stub != NULL) {
+    uint32_t aligned_code_offset = CompiledMethod::AlignCode(code_offset,
+                                                             compiler_->GetInstructionSet());
+    uint32_t aligned_code_delta = aligned_code_offset - code_offset;
+    if (aligned_code_delta != 0) {
+      off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
+      if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
+        PLOG(ERROR) << "Failed to seek to align invoke stub code. Actual: " << new_offset
+                    << " Expected: " << aligned_code_offset;
+        return false;
+      }
+      code_offset += aligned_code_delta;
+      DCHECK_CODE_OFFSET();
+    }
+    DCHECK(IsAligned(code_offset, kArmAlignment)) << std::hex << code_offset;
+    const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
+    size_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
+    DCHECK((invoke_stub_size == 0 && method->GetOatInvokeStubOffset() == 0)
+           || code_offset == method->GetOatInvokeStubOffset());
+    if (!file->WriteFully(&invoke_stub[0], invoke_stub_size)) {
+      PLOG(ERROR) << "Failed to write invoke stub code for " << PrettyMethod(method);
+      return false;
+    }
+    code_offset += invoke_stub_size;
+    DCHECK_CODE_OFFSET();
+  }
+
   return code_offset;
 }
 
diff --git a/src/oat_writer.h b/src/oat_writer.h
index 7cef892..a33ffc7 100644
--- a/src/oat_writer.h
+++ b/src/oat_writer.h
@@ -8,6 +8,7 @@
 #include <cstddef>
 
 #include "UniquePtr.h"
+#include "compiler.h"
 #include "dex_cache.h"
 #include "mem_map.h"
 #include "oat.h"
@@ -30,29 +31,33 @@
 // OatClasses[D]
 //
 // OatMethods[0]     one variable sized OatMethods for each of C DexFile::ClassDefs
-// OatMethods[1]     contains offsets to code
+// OatMethods[1]     contains OatMethod entries with offsets to code, method properities, etc.
 // ...
 // OatMethods[C]
 //
 // padding           if necessary so that the follow code will be page aligned
 //
-// Method::GetCode() one variable sized code blob for each Method::GetCode() value
-// Method::GetCode()
-// Method::GetCode()
-// Method::GetCode()
-// Method::GetCode()
-// Method::GetCode()
+// CompiledMethod    one variable sized blob with the contents of each CompiledMethod
+// CompiledMethod
+// CompiledMethod
+// CompiledMethod
+// CompiledMethod
+// CompiledMethod
 // ...
-// Method::GetCode()
+// CompiledMethod
 //
 class OatWriter {
  public:
   // Write an oat file. Returns true on success, false on failure.
-  static bool Create(const std::string& filename, const ClassLoader* class_loader);
+  static bool Create(const std::string& filename,
+                     const ClassLoader* class_loader,
+                     const Compiler& compiler);
 
  private:
 
-  OatWriter(const std::vector<const DexFile*>& dex_files, const ClassLoader* class_loader);
+  OatWriter(const std::vector<const DexFile*>& dex_files,
+            const ClassLoader* class_loader,
+            const Compiler& compiler);
   ~OatWriter();
 
   size_t InitOatHeader();
@@ -128,12 +133,14 @@
     bool Write(File* file) const;
 
     // data to write
-    std::vector<uint32_t> method_offsets_;
+    std::vector<OatMethodOffsets> method_offsets_;
 
    private:
     DISALLOW_COPY_AND_ASSIGN(OatMethods);
   };
 
+  const Compiler* compiler_;
+
   // TODO: remove the ClassLoader when the code storage moves out of Method
   const ClassLoader* class_loader_;
 
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 27dbdee..8113c2b 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -165,34 +165,12 @@
     //               object_bytes, RoundUp(object_bytes, kObjectAlignment) - object_bytes);
     if (obj->IsMethod()) {
       Method* method = obj->AsMethod();
-      if (!method->IsPhony()) {
-        const ByteArray* code = method->GetCodeArray();
-        const int8_t* code_base = NULL;
-        const int8_t* code_limit = NULL;
-        if (code != NULL) {
-          size_t code_bytes = code->GetLength();
-          code_base = code->GetData();
-          code_limit = code_base + code_bytes;
-          if (method->IsNative()) {
-            state->stats_.managed_to_native_code_bytes += code_bytes;
-          } else {
-            state->stats_.managed_code_bytes += code_bytes;
-          }
-        } else {
-          code_base = reinterpret_cast<const int8_t*>(method->GetCode());
-        }
-        StringAppendF(&summary, "\tCODE     %p-%p\n", code_base, code_limit);
+      if (!method->IsCalleeSaveMethod()) {
+        const int8_t* code =reinterpret_cast<const int8_t*>(method->GetCode());
+        StringAppendF(&summary, "\tCODE     %p\n", code);
 
-        const ByteArray* invoke = method->GetInvokeStubArray();
-        const int8_t* invoke_base = NULL;
-        const int8_t* invoke_limit = NULL;
-        if (invoke != NULL) {
-          size_t native_to_managed_code_bytes = invoke->GetLength();
-          invoke_base = invoke->GetData();
-          invoke_limit = invoke_base + native_to_managed_code_bytes;
-          state->stats_.native_to_managed_code_bytes += native_to_managed_code_bytes;
-          StringAppendF(&summary, "\tJNI STUB %p-%p\n", invoke_base, invoke_limit);
-        }
+        const Method::InvokeStub* invoke_stub = method->GetInvokeStub();
+        StringAppendF(&summary, "\tJNI STUB %p\n", invoke_stub);
       }
       if (method->IsNative()) {
         if (method->IsRegistered()) {
@@ -200,26 +178,26 @@
         } else {
           StringAppendF(&summary, "\tNATIVE UNREGISTERED\n");
         }
-        DCHECK(method->GetRegisterMapHeader() == NULL);
-        DCHECK(method->GetRegisterMapData() == NULL);
-        DCHECK(method->GetMappingTable() == NULL);
+        DCHECK(method->GetRegisterMapHeader() == NULL) << PrettyMethod(method);
+        DCHECK(method->GetRegisterMapData() == NULL) << PrettyMethod(method);
+        DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
       } else if (method->IsAbstract()) {
         StringAppendF(&summary, "\tABSTRACT\n");
-        DCHECK(method->GetRegisterMapHeader() == NULL);
-        DCHECK(method->GetRegisterMapData() == NULL);
-        DCHECK(method->GetMappingTable() == NULL);
-      } else if (method->IsPhony()) {
-        StringAppendF(&summary, "\tPHONY\n");
-        DCHECK(method->GetRegisterMapHeader() == NULL);
-        DCHECK(method->GetRegisterMapData() == NULL);
-        DCHECK(method->GetMappingTable() == NULL);
+        DCHECK(method->GetRegisterMapHeader() == NULL) << PrettyMethod(method);
+        DCHECK(method->GetRegisterMapData() == NULL) << PrettyMethod(method);
+        DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
+      } else if (method->IsCalleeSaveMethod()) {
+        StringAppendF(&summary, "\tCALLEE SAVE METHOD\n");
+        DCHECK(method->GetRegisterMapHeader() == NULL) << PrettyMethod(method);
+        DCHECK(method->GetRegisterMapData() == NULL) << PrettyMethod(method);
+        DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
       } else {
         size_t register_map_bytes = (method->GetRegisterMapHeader()->GetLength() +
                                      method->GetRegisterMapData()->GetLength());
         state->stats_.register_map_bytes += register_map_bytes;
 
         if (method->GetMappingTable() != NULL) {
-          size_t pc_mapping_table_bytes = method->GetMappingTable()->GetLength();
+          size_t pc_mapping_table_bytes = method->GetMappingTableLength();
           state->stats_.pc_mapping_table_bytes += pc_mapping_table_bytes;
         }
 
diff --git a/src/oatexec.cc b/src/oatexec.cc
index 9632ca2..f1d63c3 100644
--- a/src/oatexec.cc
+++ b/src/oatexec.cc
@@ -17,20 +17,20 @@
 static bool IsMethodPublic(JNIEnv* env, jclass clazz, jmethodID method_id) {
   ScopedLocalRef<jobject> reflected(env, env->ToReflectedMethod(clazz, method_id, JNI_FALSE));
   if (reflected.get() == NULL) {
-    fprintf(stderr, "Unable to get reflected method\n");
+    fprintf(stderr, "Failed to get reflected method\n");
     return false;
   }
   // We now have a Method instance.  We need to call its
   // getModifiers() method.
   ScopedLocalRef<jclass> method(env, env->FindClass("java/lang/reflect/Method"));
   if (method.get() == NULL) {
-    fprintf(stderr, "Unable to find class Method\n");
+    fprintf(stderr, "Failed to find class Method\n");
     return false;
   }
   static const int PUBLIC = 0x0001;   // java.lang.reflect.Modifiers.PUBLIC
   jmethodID get_modifiers = env->GetMethodID(method.get(), "getModifiers", "()I");
   if (get_modifiers == NULL) {
-    fprintf(stderr, "Unable to find reflect.Method.getModifiers\n");
+    fprintf(stderr, "Failed to find reflect.Method.getModifiers\n");
     return false;
   }
   int modifiers = env->CallIntMethod(reflected.get(), get_modifiers);
diff --git a/src/object.cc b/src/object.cc
index c43fe49..99cdbc8 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -620,21 +620,18 @@
 }
 
 uint32_t Method::ToDexPC(const uintptr_t pc) const {
-  IntArray* mapping_table = GetMappingTable();
+  const uint32_t* mapping_table = GetMappingTable();
   if (mapping_table == NULL) {
     DCHECK(IsNative());
     return DexFile::kDexNoIndex;   // Special no mapping case
   }
-  size_t mapping_table_length = mapping_table->GetLength();
+  size_t mapping_table_length = GetMappingTableLength();
   uint32_t sought_offset = pc - reinterpret_cast<uintptr_t>(GetCode());
-  if (GetCodeArray() != NULL) {
-    CHECK_LT(sought_offset, static_cast<uint32_t>(GetCodeArray()->GetLength()));
-  }
   uint32_t best_offset = 0;
   uint32_t best_dex_offset = 0;
   for (size_t i = 0; i < mapping_table_length; i += 2) {
-    uint32_t map_offset = mapping_table->Get(i);
-    uint32_t map_dex_offset = mapping_table->Get(i + 1);
+    uint32_t map_offset = mapping_table[i];
+    uint32_t map_dex_offset = mapping_table[i + 1];
     if (map_offset == sought_offset) {
       best_offset = map_offset;
       best_dex_offset = map_dex_offset;
@@ -649,19 +646,16 @@
 }
 
 uintptr_t Method::ToNativePC(const uint32_t dex_pc) const {
-  IntArray* mapping_table = GetMappingTable();
+  const uint32_t* mapping_table = GetMappingTable();
   if (mapping_table == NULL) {
     DCHECK(dex_pc == 0);
     return 0;   // Special no mapping/pc == 0 case
   }
-  size_t mapping_table_length = mapping_table->GetLength();
+  size_t mapping_table_length = GetMappingTableLength();
   for (size_t i = 0; i < mapping_table_length; i += 2) {
-    uint32_t map_offset = mapping_table->Get(i);
-    uint32_t map_dex_offset = mapping_table->Get(i + 1);
+    uint32_t map_offset = mapping_table[i];
+    uint32_t map_dex_offset = mapping_table[i + 1];
     if (map_dex_offset == dex_pc) {
-      if (GetCodeArray() != NULL) {
-        DCHECK_LT(map_offset, static_cast<uint32_t>(GetCodeArray()->GetLength()));
-      }
       return reinterpret_cast<uintptr_t>(GetCode()) + map_offset;
     }
   }
@@ -694,58 +688,6 @@
   return DexFile::kDexNoIndex;
 }
 
-void Method::SetCodeArray(ByteArray* code_array, InstructionSet instruction_set) {
-// TODO: restore this check or warning when compile time code storage is moved out of Method
-//  CHECK(GetCode() == NULL || IsNative()) << PrettyMethod(this);
-//  if (GetCode() != NULL && !IsNative()) {
-//    LOG(WARNING) << "Calling SetCode more than once for " << PrettyMethod(this);
-//  }
-  SetFieldPtr<ByteArray*>(OFFSET_OF_OBJECT_MEMBER(Method, code_array_), code_array, false);
-
-  void* code;
-  if (code_array != NULL) {
-    code = code_array->GetData();
-    if (instruction_set == kThumb2) {
-      uintptr_t address = reinterpret_cast<uintptr_t>(code);
-      // Set the low-order bit so a BLX will switch to Thumb mode
-      address |= 0x1;
-      code = reinterpret_cast<void*>(address);
-    }
-  } else {
-    code = NULL;
-  }
-  SetCode(code);
-}
-
-bool Method::IsWithinCode(uintptr_t pc) const {
-  if (pc == 0) {
-    // PC of 0 represents the beginning of a stack trace either a native or where we have a callee
-    // save method that has no code
-    DCHECK(IsNative() || IsPhony());
-    return true;
-  } else {
-#if defined(__arm__)
-    pc &= ~0x1;  // clear any possible thumb instruction mode bit
-#endif
-    if (GetCodeArray() == NULL) {
-      return true;
-    }
-    uint32_t rel_offset = pc - reinterpret_cast<uintptr_t>(GetCodeArray()->GetData());
-    // Strictly the following test should be a less-than, however, if the last
-    // instruction is a call to an exception throw we may see return addresses
-    // that are 1 beyond the end of code.
-    return rel_offset <= static_cast<uint32_t>(GetCodeArray()->GetLength());
-  }
-}
-
-void Method::SetInvokeStub(const ByteArray* invoke_stub_array) {
-  const InvokeStub* invoke_stub = reinterpret_cast<InvokeStub*>(invoke_stub_array->GetData());
-  SetFieldPtr<const ByteArray*>(
-      OFFSET_OF_OBJECT_MEMBER(Method, invoke_stub_array_), invoke_stub_array, false);
-  SetFieldPtr<const InvokeStub*>(
-      OFFSET_OF_OBJECT_MEMBER(Method, invoke_stub_), invoke_stub, false);
-}
-
 void Method::Invoke(Thread* self, Object* receiver, byte* args, JValue* result) const {
   // Push a transition back into managed code onto the linked list in thread.
   CHECK_EQ(Thread::kRunnable, self->GetState());
@@ -779,7 +721,7 @@
   self->PopNativeToManagedRecord(record);
 }
 
-bool Method::IsRegistered() {
+bool Method::IsRegistered() const {
   void* native_method = GetFieldPtr<void*>(OFFSET_OF_OBJECT_MEMBER(Method, native_method_), false);
   void* jni_stub = Runtime::Current()->GetJniStubArray()->GetData();
   return native_method != jni_stub;
diff --git a/src/object.h b/src/object.h
index 03fa359..de3075b 100644
--- a/src/object.h
+++ b/src/object.h
@@ -404,6 +404,16 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(Object);
 };
 
+struct ObjectIdentityHash {
+  size_t operator()(const art::Object* const& obj) const {
+#ifdef MOVING_GARBAGE_COLLECTOR
+  // TODO: we'll need to use the Object's internal concept of identity
+    UNIMPLEMENTED(FATAL);
+#endif
+    return reinterpret_cast<size_t>(obj);
+  }
+};
+
 // C++ mirror of java.lang.reflect.AccessibleObject
 class MANAGED AccessibleObject : public Object {
  private:
@@ -667,8 +677,7 @@
   }
 
   void SetMethodIndex(uint16_t new_method_index) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(Method, method_index_),
-               new_method_index, false);
+    SetField32(OFFSET_OF_OBJECT_MEMBER(Method, method_index_), new_method_index, false);
   }
 
   static MemberOffset MethodIndexOffset() {
@@ -680,8 +689,7 @@
   }
 
   void SetCodeItemOffset(uint32_t new_code_off) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(Method, code_item_offset_),
-               new_code_off, false);
+    SetField32(OFFSET_OF_OBJECT_MEMBER(Method, code_item_offset_), new_code_off, false);
   }
 
   // Number of 32bit registers that would be required to hold all the arguments
@@ -694,22 +702,19 @@
   uint16_t NumRegisters() const;
 
   void SetNumRegisters(uint16_t new_num_registers) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_registers_),
-               new_num_registers, false);
+    SetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_registers_), new_num_registers, false);
   }
 
   uint16_t NumIns() const;
 
   void SetNumIns(uint16_t new_num_ins) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_ins_),
-               new_num_ins, false);
+    SetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_ins_), new_num_ins, false);
   }
 
   uint16_t NumOuts() const;
 
   void SetNumOuts(uint16_t new_num_outs) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_outs_),
-               new_num_outs, false);
+    SetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_outs_), new_num_outs, false);
   }
 
   uint32_t GetProtoIdx() const;
@@ -806,15 +811,11 @@
 
   void Invoke(Thread* self, Object* receiver, byte* args, JValue* result) const;
 
-  const ByteArray* GetCodeArray() const {
-    return GetFieldPtr<const ByteArray*>(OFFSET_OF_OBJECT_MEMBER(Method, code_array_), false);
-  }
-
   const void* GetCode() const {
     return GetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(Method, code_), false);
   }
 
-  void SetCode(void* code) {
+  void SetCode(const void* code) {
     SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(Method, code_), code, false);
   }
 
@@ -828,29 +829,77 @@
     SetCode(reinterpret_cast<void*>(code_offset));
   }
 
-  void SetCodeArray(ByteArray* code_array, InstructionSet instruction_set);
-
   static MemberOffset GetCodeOffset() {
     return OFFSET_OF_OBJECT_MEMBER(Method, code_);
   }
 
-  // Is the given PC within the code array?
-  bool IsWithinCode(uintptr_t pc) const;
-
-  IntArray* GetMappingTable() const {
-    return GetFieldObject<IntArray*>(OFFSET_OF_OBJECT_MEMBER(Method, mapping_table_), false);
+  const uint32_t* GetMappingTable() const {
+    const uint32_t* map = GetMappingTableRaw();
+    if (map == NULL) {
+      return map;
+    }
+    return map + 1;
   }
 
-  void SetMappingTable(IntArray* mapping_table) {
-    SetFieldPtr<IntArray*>(OFFSET_OF_OBJECT_MEMBER(Method, mapping_table_), mapping_table, false);
+  uint32_t GetMappingTableLength() const {
+    const uint32_t* map = GetMappingTableRaw();
+    if (map == NULL) {
+      return 0;
+    }
+    return *map;
   }
 
-  ShortArray* GetVMapTable() const {
-    return GetFieldObject<ShortArray*>(OFFSET_OF_OBJECT_MEMBER(Method, vmap_table_), false);
+  const uint32_t* GetMappingTableRaw() const {
+    return GetFieldPtr<const uint32_t*>(OFFSET_OF_OBJECT_MEMBER(Method, mapping_table_), false);
   }
 
-  void SetVMapTable(ShortArray* vmap_table) {
-    SetFieldPtr<ShortArray*>(OFFSET_OF_OBJECT_MEMBER(Method, vmap_table_), vmap_table, false);
+  void SetMappingTable(const uint32_t* mapping_table) {
+    SetFieldPtr<const uint32_t*>(OFFSET_OF_OBJECT_MEMBER(Method, mapping_table_),
+                                 mapping_table, false);
+  }
+
+  uint32_t GetOatMappingTableOffset() const {
+    CHECK(!Runtime::Current()->IsStarted());
+    return reinterpret_cast<uint32_t>(GetMappingTableRaw());
+  }
+
+  void SetOatMappingTableOffset(uint32_t mapping_table_offset) {
+    CHECK(!Runtime::Current()->IsStarted());
+    SetMappingTable(reinterpret_cast<const uint32_t*>(mapping_table_offset));
+  }
+
+  const uint16_t* GetVmapTable() const {
+    const uint16_t* vmap = GetVmapTableRaw();
+    if (vmap == NULL) {
+      return vmap;
+    }
+    return vmap + 1;
+  }
+
+  uint16_t GetVmapTableLength() const {
+    const uint16_t* vmap = GetVmapTableRaw();
+    if (vmap == NULL) {
+      return 0;
+    }
+    return *vmap;
+  }
+
+  const uint16_t* GetVmapTableRaw() const {
+    return GetFieldPtr<const uint16_t*>(OFFSET_OF_OBJECT_MEMBER(Method, vmap_table_), false);
+  }
+
+  void SetVmapTable(const uint16_t* vmap_table) {
+    SetFieldPtr<const uint16_t*>(OFFSET_OF_OBJECT_MEMBER(Method, vmap_table_), vmap_table, false);
+  }
+
+  uint32_t GetOatVmapTableOffset() const {
+    CHECK(!Runtime::Current()->IsStarted());
+    return reinterpret_cast<uint32_t>(GetVmapTableRaw());
+  }
+
+  void SetOatVmapTableOffset(uint32_t vmap_table_offset) {
+    CHECK(!Runtime::Current()->IsStarted());
+    SetVmapTable(reinterpret_cast<uint16_t*>(vmap_table_offset));
   }
 
   size_t GetFrameSizeInBytes() const {
@@ -881,7 +930,7 @@
                return_pc_offset_in_bytes, false);
   }
 
-  bool IsRegistered();
+  bool IsRegistered() const;
 
   void RegisterNative(const void* native_method);
 
@@ -895,13 +944,6 @@
     return reinterpret_cast<const void*>(GetField32(NativeMethodOffset(), false));
   }
 
-  ByteArray* GetInvokeStubArray() const {
-    ByteArray* result = GetFieldPtr<ByteArray*>(
-        OFFSET_OF_OBJECT_MEMBER(Method, invoke_stub_array_), false);
-    // TODO: DCHECK(result != NULL);  should be ahead of time compiled
-    return result;
-  }
-
   // Native to managed invocation stub entry point
   InvokeStub* GetInvokeStub() const {
     InvokeStub* result = GetFieldPtr<InvokeStub*>(
@@ -910,6 +952,21 @@
     return result;
   }
 
+  void SetInvokeStub(InvokeStub* invoke_stub) {
+    SetFieldPtr<const InvokeStub*>(OFFSET_OF_OBJECT_MEMBER(Method, invoke_stub_),
+                                   invoke_stub, false);
+  }
+
+  uint32_t GetOatInvokeStubOffset() const {
+    CHECK(!Runtime::Current()->IsStarted());
+    return reinterpret_cast<uint32_t>(GetInvokeStub());
+  }
+
+  void SetOatInvokeStubOffset(uint32_t invoke_stub_offset) {
+    CHECK(!Runtime::Current()->IsStarted());
+    SetInvokeStub(reinterpret_cast<InvokeStub*>(invoke_stub_offset));
+  }
+
   static MemberOffset GetInvokeStubOffset() {
     return OFFSET_OF_OBJECT_MEMBER(Method, invoke_stub_);
   }
@@ -926,8 +983,6 @@
     return OFFSET_OF_OBJECT_MEMBER(Method, method_index_);
   }
 
-  void SetInvokeStub(const ByteArray* invoke_stub_array);
-
   uint32_t GetCoreSpillMask() const {
     return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, core_spill_mask_), false);
   }
@@ -947,7 +1002,7 @@
   }
 
   // Is this a hand crafted method used for something like describing callee saves?
-  bool IsPhony() const {
+  bool IsCalleeSaveMethod() const {
     Runtime* runtime = Runtime::Current();
     bool result = false;
     for (int i=0; i < Runtime::kLastCalleeSaveType; i++) {
@@ -1005,9 +1060,6 @@
   ObjectArray<Class>* java_parameter_types_;
   Class* java_return_type_;
 
-  // Storage for code_
-  const ByteArray* code_array_;
-
   // short cuts to declaring_class_->dex_cache_ member for fast compiled code access
   CodeAndDirectMethods* dex_cache_code_and_direct_methods_;
 
@@ -1026,12 +1078,6 @@
   // short cuts to declaring_class_->dex_cache_ member for fast compiled code access
   ObjectArray<String>* dex_cache_strings_;
 
-  // Storage for invoke_stub_
-  const ByteArray* invoke_stub_array_;
-
-  // Storage for mapping_table_
-  IntArray* mapping_table_;
-
   // Byte arrays that hold data for the register maps
   const ByteArray* register_map_data_;
   const ByteArray* register_map_header_;
@@ -1051,9 +1097,6 @@
   //   (IDLjava/lang/Thread;)Ljava/lang/Object;
   String* signature_;
 
-  // Storage for Dalvik virtual register mapping_table_
-  ShortArray* vmap_table_;
-
   uint32_t java_generic_types_are_initialized_;
 
   // Access flags; low 16 bits are defined by spec.
@@ -1081,6 +1124,8 @@
   // Index of the return type
   uint32_t java_return_type_idx_;
 
+  const uint32_t* mapping_table_;
+
   // For concrete virtual methods, this is the offset of the method
   // in Class::vtable_.
   //
@@ -1105,6 +1150,8 @@
   // Offset of return PC within frame for compiled code (in bytes)
   size_t return_pc_offset_in_bytes_;
 
+  const uint16_t* vmap_table_;
+
   uint32_t java_slot_;
 
   static Class* java_lang_reflect_Constructor_;
diff --git a/src/runtime.cc b/src/runtime.cc
index 7e27918..e46cf88 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -640,7 +640,7 @@
   }
   method->SetName(intern_table_->InternStrong(name));
   method->SetSignature(intern_table_->InternStrong("()V"));
-  method->SetCodeArray(NULL, insns);
+  method->SetCode(NULL);
   if ((insns == kThumb2) || (insns == kArm)) {
     uint32_t ref_spills = (1 << art::arm::R5) | (1 << art::arm::R6)  | (1 << art::arm::R7) |
                           (1 << art::arm::R8) | (1 << art::arm::R10) | (1 << art::arm::R11);
diff --git a/src/space.cc b/src/space.cc
index 248f7e8..ae35f57 100644
--- a/src/space.cc
+++ b/src/space.cc
@@ -115,7 +115,7 @@
   }
   UniquePtr<MemMap> map(MemMap::Map(image_header.GetImageBaseAddr(),
                                     file->Length(),
-                                    // TODO: selectively PROT_EXEC when image contains a code space
+                                    // TODO: selectively PROT_EXEC an image subset containing stubs
                                     PROT_READ | PROT_WRITE | PROT_EXEC,
                                     MAP_PRIVATE | MAP_FIXED,
                                     file->Fd(),
diff --git a/src/stack.cc b/src/stack.cc
index 9f01dab..985fd38 100644
--- a/src/stack.cc
+++ b/src/stack.cc
@@ -19,10 +19,12 @@
 #include "compiler.h"
 #include "object.h"
 
+int oatVRegOffsetFromMethod(art::Method* method, int reg);
+
 namespace art {
 
 bool Frame::HasMethod() const {
-  return GetMethod() != NULL && (!GetMethod()->IsPhony());
+  return GetMethod() != NULL && (!GetMethod()->IsCalleeSaveMethod());
 }
 
 void Frame::Next() {
diff --git a/src/stack_walk.cc b/src/stack_walk.cc
index 2c29e75..a1f6e0f 100644
--- a/src/stack_walk.cc
+++ b/src/stack_walk.cc
@@ -43,7 +43,7 @@
       // pc == NULL: m is either a native method or a phony method
       return;
     }
-    if (m->IsPhony()) {
+    if (m->IsCalleeSaveMethod()) {
       LOG(WARNING) << "no PC for " << PrettyMethod(m);
       return;
     }
diff --git a/src/thread.cc b/src/thread.cc
index 532b581..c50bf0a 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -968,7 +968,7 @@
 
   while (frame.GetSP() != 0) {
     for ( ; frame.GetMethod() != 0; frame.Next()) {
-      DCHECK(frame.GetMethod()->IsWithinCode(pc));
+      // DCHECK(frame.GetMethod()->IsWithinCode(pc));  // TODO: restore IsWithinCode
       visitor->VisitFrame(frame, pc);
       pc = frame.GetReturnPC();
       // Move the PC back 2 bytes as a call will frequently terminate the
@@ -993,7 +993,7 @@
 
   if (frame.GetSP() != 0) {
     for ( ; frame.GetMethod() != 0; frame.Next()) {
-      DCHECK(frame.GetMethod()->IsWithinCode(pc));
+      // DCHECK(frame.GetMethod()->IsWithinCode(pc));  // TODO: restore IsWithinCode
       visitor->VisitFrame(frame, pc);
       pc = frame.GetReturnPC();
       // Move the PC back 2 bytes as a call will frequently terminate the
@@ -1143,7 +1143,7 @@
         return;
       }
       uint32_t dex_pc = DexFile::kDexNoIndex;
-      if (method->IsPhony()) {
+      if (method->IsCalleeSaveMethod()) {
         // ignore callee save method
       } else if (method->IsNative()) {
         native_method_count_++;
@@ -1229,13 +1229,13 @@
   void VisitFrame(const Frame& frame, uintptr_t pc) {
     Method* m = frame.GetMethod();
     // Process register map (which native and callee save methods don't have)
-    if (!m->IsNative() && !m->IsPhony()) {
+    if (!m->IsNative() && !m->IsCalleeSaveMethod()) {
       UniquePtr<art::DexVerifier::RegisterMap> map(art::DexVerifier::GetExpandedRegisterMap(m));
       const uint8_t* reg_bitmap = art::DexVerifier::RegisterMapGetLine(map.get(), m->ToDexPC(pc));
       LOG(INFO) << "Visiting stack roots in " << PrettyMethod(m, false)
                 << "@ PC: " << m->ToDexPC(pc);
       CHECK(reg_bitmap != NULL);
-      ShortArray* vmap = m->GetVMapTable();
+      const uint16_t* vmap = m->GetVmapTable();
       // For all dex registers
       for (int reg = 0; reg < m->NumRegisters(); ++reg) {
         // Does this register hold a reference?
@@ -1244,8 +1244,8 @@
           bool in_context = false;
           uint32_t vmap_offset = 0xEBAD0FF5;
           // TODO: take advantage of the registers being ordered
-          for (int i = 0; i < vmap->GetLength(); i++) {
-            if (vmap->Get(i) == reg) {
+          for (int i = 0; i < m->GetVmapTableLength(); i++) {
+            if (vmap[i] == reg) {
               in_context = true;
               vmap_offset = i;
               break;