Invoke static/direct dispatch change.

There was a subtle race in static/direct dispatch via the code and methods
table. This patch removes the table in preparation of architectures like
x86 which will more aggressively sink loads.

Removes unused fields, code.. Brings back resolved methods table
short-cut and associated fast paths to use this (such as in Proxy). Adds
a resolution method that is used as the trampoline for static and direct
methods.

Add source file and line number to Throwable::Dump.

MethodHelper knowledge of runtime methods.

Change-Id: Ieae1b74c24072e6327a5bb2cad466f04e3c46c4d
diff --git a/src/class_linker.cc b/src/class_linker.cc
index f48a25c..b40449c 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1041,10 +1041,6 @@
   if (fields.get() == NULL) {
     return NULL;
   }
-  SirtRef<CodeAndDirectMethods> code_and_direct_methods(AllocCodeAndDirectMethods(dex_file.NumMethodIds()));
-  if (code_and_direct_methods.get() == NULL) {
-    return NULL;
-  }
   SirtRef<ObjectArray<StaticStorageBase> > initialized_static_storage(AllocObjectArray<StaticStorageBase>(dex_file.NumTypeIds()));
   if (initialized_static_storage.get() == NULL) {
     return NULL;
@@ -1055,15 +1051,10 @@
                   types.get(),
                   methods.get(),
                   fields.get(),
-                  code_and_direct_methods.get(),
                   initialized_static_storage.get());
   return dex_cache.get();
 }
 
-CodeAndDirectMethods* ClassLinker::AllocCodeAndDirectMethods(size_t length) {
-  return down_cast<CodeAndDirectMethods*>(IntArray::Alloc(CodeAndDirectMethods::LengthAsArray(length)));
-}
-
 InterfaceEntry* ClassLinker::AllocInterfaceEntry(Class* interface) {
   DCHECK(interface->IsInterface());
   SirtRef<ObjectArray<Object> > array(AllocObjectArray<Object>(InterfaceEntry::LengthAsArray()));
@@ -1327,19 +1318,89 @@
   return size;
 }
 
+const OatFile::OatClass* ClassLinker::GetOatClass(const DexFile& dex_file, const char* descriptor) {
+  DCHECK(descriptor != NULL);
+  if (!Runtime::Current()->IsStarted() || ClassLoader::UseCompileTimeClassPath()) {
+    return NULL;
+  }
+  const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file);
+  CHECK(oat_file != NULL) << dex_file.GetLocation() << " " << descriptor;
+  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
+  CHECK(oat_dex_file != NULL) << dex_file.GetLocation() << " " << descriptor;
+  uint32_t class_def_index;
+  bool found = dex_file.FindClassDefIndex(descriptor, class_def_index);
+  CHECK(found) << dex_file.GetLocation() << " " << descriptor;
+  const OatFile::OatClass* oat_class = oat_dex_file->GetOatClass(class_def_index);
+  CHECK(oat_class != NULL) << dex_file.GetLocation() << " " << descriptor;
+  return oat_class;
+}
+
+const void* ClassLinker::GetOatCodeFor(const Method* method) {
+  // Special case to get oat code without overwriting a trampoline.
+  CHECK(method->GetDeclaringClass()->IsInitializing());
+  // Although we overwrite the trampoline of non-static methods, we may get here via the resolution
+  // method for direct methods.
+  CHECK(method->IsStatic() || method->IsDirect());
+  ClassHelper kh(method->GetDeclaringClass());
+  UniquePtr<const OatFile::OatClass> oat_class(GetOatClass(kh.GetDexFile(), kh.GetDescriptor()));
+  size_t method_index = method->GetMethodIndex();
+  return oat_class->GetOatMethod(method_index).GetCode();
+}
+
+void ClassLinker::FixupStaticTrampolines(Class* klass) {
+  ClassHelper kh(klass);
+  const DexFile::ClassDef* dex_class_def = kh.GetClassDef();
+  CHECK(dex_class_def != NULL);
+  const DexFile& dex_file = kh.GetDexFile();
+  const byte* class_data = dex_file.GetClassData(*dex_class_def);
+  if (class_data == NULL) {
+    return;  // no fields or methods - for example a marker interface
+  }
+  UniquePtr<const OatFile::OatClass> oat_class(GetOatClass(dex_file, kh.GetDescriptor()));
+  if (oat_class.get() == NULL) {
+    // OAT file unavailable
+    return;
+  }
+  ClassDataItemIterator it(dex_file, class_data);
+  // Skip fields
+  while (it.HasNextStaticField()) {
+    it.Next();
+  }
+  while (it.HasNextInstanceField()) {
+    it.Next();
+  }
+  size_t method_index = 0;
+  // Link the code of methods skipped by LinkCode
+  const void* trampoline = Runtime::Current()->GetResolutionStubArray(Runtime::kStaticMethod)->GetData();
+  for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) {
+    Method* method = klass->GetDirectMethod(i);
+    if (method->GetCode() == trampoline) {
+      const void* code = oat_class->GetOatMethod(method_index).GetCode();
+      CHECK(code != NULL);
+      method->SetCode(code);
+    }
+    method_index++;
+  }
+}
+
 void LinkCode(SirtRef<Method>& method, const OatFile::OatClass* oat_class, uint32_t method_index) {
   // Every kind of method should at least get an invoke stub from the oat_method.
   // non-abstract methods also get their code pointers.
   const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index);
   oat_method.LinkMethodPointers(method.get());
 
+  Runtime* runtime = Runtime::Current();
   if (method->IsAbstract()) {
-    method->SetCode(Runtime::Current()->GetAbstractMethodErrorStubArray()->GetData());
+    method->SetCode(runtime->GetAbstractMethodErrorStubArray()->GetData());
     return;
   }
-  if (method->IsNative()) {
+
+  if (method->IsStatic() && !method->IsConstructor()) {
+    // For static methods excluding the class initializer, install the trampoline
+    method->SetCode(runtime->GetResolutionStubArray(Runtime::kStaticMethod)->GetData());
+  } else if (method->IsNative()) {
     // unregistering restores the dlsym lookup stub
-    method->UnregisterNative();
+    method->UnregisterNative(Thread::Current());
   }
 
   if (Runtime::Current()->IsMethodTracingActive()) {
@@ -1397,18 +1458,8 @@
     LoadField(dex_file, it, klass, ifield);
   }
 
-  UniquePtr<const OatFile::OatClass> oat_class;
-  if (Runtime::Current()->IsStarted() && !ClassLoader::UseCompileTimeClassPath()) {
-    const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file);
-    CHECK(oat_file != NULL) << dex_file.GetLocation() << " " << descriptor;
-    const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
-    CHECK(oat_dex_file != NULL) << dex_file.GetLocation() << " " << descriptor;
-    uint32_t class_def_index;
-    bool found = dex_file.FindClassDefIndex(descriptor, class_def_index);
-    CHECK(found) << dex_file.GetLocation() << " " << descriptor;
-    oat_class.reset(oat_dex_file->GetOatClass(class_def_index));
-    CHECK(oat_class.get() != NULL) << dex_file.GetLocation() << " " << descriptor;
-  }
+  UniquePtr<const OatFile::OatClass> oat_class(GetOatClass(dex_file, descriptor));
+
   // Load methods.
   if (it.NumDirectMethods() != 0) {
     // TODO: append direct methods to class object
@@ -1426,6 +1477,7 @@
     if (oat_class.get() != NULL) {
       LinkCode(method, oat_class.get(), method_index);
     }
+    method->SetMethodIndex(method_index);
     method_index++;
   }
   for (size_t i = 0; it.HasNextVirtualMethod(); i++, it.Next()) {
@@ -1450,9 +1502,9 @@
 
 void ClassLinker::LoadMethod(const DexFile& dex_file, const ClassDataItemIterator& it,
                              SirtRef<Class>& klass, SirtRef<Method>& dst) {
-  uint32_t method_idx = it.GetMemberIndex();
-  dst->SetDexMethodIndex(method_idx);
-  const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
+  uint32_t dex_method_idx = it.GetMemberIndex();
+  dst->SetDexMethodIndex(dex_method_idx);
+  const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
   dst->SetDeclaringClass(klass.get());
 
 
@@ -1495,8 +1547,8 @@
   dst->SetAccessFlags(it.GetMemberAccessFlags());
 
   dst->SetDexCacheStrings(klass->GetDexCache()->GetStrings());
+  dst->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods());
   dst->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes());
-  dst->SetDexCacheCodeAndDirectMethods(klass->GetDexCache()->GetCodeAndDirectMethods());
   dst->SetDexCacheInitializedStaticStorage(klass->GetDexCache()->GetInitializedStaticStorage());
 }
 
@@ -1515,7 +1567,7 @@
   dex_lock_.AssertHeld();
   for (size_t i = 0; i != dex_files_.size(); ++i) {
     if (dex_files_[i] == &dex_file) {
-        return true;
+      return true;
     }
   }
   return false;
@@ -1564,7 +1616,7 @@
   MutexLock mu(dex_lock_);
   for (size_t i = 0; i != dex_caches_.size(); ++i) {
     if (dex_caches_[i] == dex_cache) {
-        return *dex_files_[i];
+      return *dex_files_[i];
     }
   }
   CHECK(false) << "Failed to find DexFile for DexCache " << dex_cache->GetLocation()->ToModifiedUtf8();
@@ -1575,13 +1627,20 @@
   MutexLock mu(dex_lock_);
   for (size_t i = 0; i != dex_files_.size(); ++i) {
     if (dex_files_[i] == &dex_file) {
-        return dex_caches_[i];
+      return dex_caches_[i];
     }
   }
   CHECK(false) << "Failed to find DexCache for DexFile " << dex_file.GetLocation();
   return NULL;
 }
 
+void ClassLinker::FixupDexCaches(Method* resolution_method) const {
+  MutexLock mu(dex_lock_);
+  for (size_t i = 0; i != dex_caches_.size(); ++i) {
+    dex_caches_[i]->Fixup(resolution_method);
+  }
+}
+
 Class* ClassLinker::InitializePrimitiveClass(Class* primitive_class,
                                              const char* descriptor,
                                              Primitive::Type type) {
@@ -2195,18 +2254,22 @@
   CHECK(!prototype->IsFinal());
   CHECK(method->IsFinal());
   CHECK(!method->IsAbstract());
+
+  // The proxy method doesn't have its own dex cache or dex file and so it steals those of its
+  // interface prototype. The exception to this are Constructors and the Class of the Proxy itself.
+  CHECK_EQ(prototype->GetDexCacheStrings(), method->GetDexCacheStrings());
+  CHECK_EQ(prototype->GetDexCacheResolvedMethods(), method->GetDexCacheResolvedMethods());
+  CHECK_EQ(prototype->GetDexCacheResolvedTypes(), method->GetDexCacheResolvedTypes());
+  CHECK_EQ(prototype->GetDexCacheInitializedStaticStorage(),
+           method->GetDexCacheInitializedStaticStorage());
+  CHECK_EQ(prototype->GetDexMethodIndex(), method->GetDexMethodIndex());
+
   MethodHelper mh(method);
-  const char* method_name = mh.GetName();
-  const char* method_shorty = mh.GetShorty();
-  Class* method_return = mh.GetReturnType();
-
-  mh.ChangeMethod(prototype.get());
-
-  CHECK_STREQ(mh.GetName(), method_name);
-  CHECK_STREQ(mh.GetShorty(), method_shorty);
-
+  MethodHelper mh2(prototype.get());
+  CHECK_STREQ(mh.GetName(), mh2.GetName());
+  CHECK_STREQ(mh.GetShorty(), mh2.GetShorty());
   // More complex sanity - via dex cache
-  CHECK_EQ(mh.GetReturnType(), method_return);
+  CHECK_EQ(mh.GetReturnType(), mh2.GetReturnType());
 }
 
 bool ClassLinker::InitializeClass(Class* klass, bool can_run_clinit) {
@@ -2242,6 +2305,8 @@
       // if the class has a <clinit> but we can't run it during compilation,
       // don't bother going to kStatusInitializing. We return false so that
       // sub-classes don't believe this class is initialized.
+      // Opportunistically link non-static methods, TODO: don't initialize and dirty pages
+      // in second pass.
       return false;
     }
 
@@ -2291,6 +2356,8 @@
     clinit->Invoke(self, NULL, NULL, NULL);
   }
 
+  FixupStaticTrampolines(klass);
+
   uint64_t t1 = NanoTime();
 
   bool success = true;
@@ -3307,12 +3374,12 @@
   return resolved;
 }
 
-const char* ClassLinker::MethodShorty(uint32_t method_idx, Method* referrer) {
+const char* ClassLinker::MethodShorty(uint32_t method_idx, Method* referrer, uint32_t* length) {
   Class* declaring_class = referrer->GetDeclaringClass();
   DexCache* dex_cache = declaring_class->GetDexCache();
   const DexFile& dex_file = FindDexFile(dex_cache);
   const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
-  return dex_file.GetShorty(method_id.proto_idx_);
+  return dex_file.GetMethodShorty(method_id, length);
 }
 
 void ClassLinker::DumpAllClasses(int flags) const {
diff --git a/src/class_linker.h b/src/class_linker.h
index f9c190e..9ba79eb 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -159,10 +159,10 @@
                         bool is_direct);
 
   Method* ResolveMethod(uint32_t method_idx, const Method* referrer, bool is_direct) {
-    Class* declaring_class = referrer->GetDeclaringClass();
-    DexCache* dex_cache = declaring_class->GetDexCache();
-    Method* resolved_method = dex_cache->GetResolvedMethod(method_idx);
-    if (UNLIKELY(resolved_method == NULL)) {
+    Method* resolved_method = referrer->GetDexCacheResolvedMethods()->Get(method_idx);
+    if (UNLIKELY(resolved_method == NULL || resolved_method->IsRuntimeMethod())) {
+      Class* declaring_class = referrer->GetDeclaringClass();
+      DexCache* dex_cache = declaring_class->GetDexCache();
       const ClassLoader* class_loader = declaring_class->GetClassLoader();
       const DexFile& dex_file = FindDexFile(dex_cache);
       resolved_method = ResolveMethod(dex_file, method_idx, dex_cache, class_loader, is_direct);
@@ -217,7 +217,7 @@
                          const ClassLoader* class_loader);
 
   // Get shorty from method index without resolution. Used to do handlerization.
-  const char* MethodShorty(uint32_t method_idx, Method* referrer);
+  const char* MethodShorty(uint32_t method_idx, Method* referrer, uint32_t* length);
 
   // Returns true on success, false if there's an exception pending.
   // can_run_clinit=false allows the compiler to attempt to init a class,
@@ -244,6 +244,7 @@
   const DexFile& FindDexFile(const DexCache* dex_cache) const;
   DexCache* FindDexCache(const DexFile& dex_file) const;
   bool IsDexFileRegistered(const DexFile& dex_file) const;
+  void FixupDexCaches(Method* resolution_method) const;
 
   // Generate an oat file from a dex file
   bool GenerateOatFile(const std::string& dex_filename,
@@ -285,6 +286,9 @@
   std::string GetDescriptorForProxy(const Class* proxy_class);
   Method* FindMethodForProxy(const Class* proxy_class, const Method* proxy_method);
 
+  // Get the oat code for a method when its class isn't yet initialized
+  const void* GetOatCodeFor(const Method* method);
+
   pid_t GetClassesLockOwner(); // For SignalCatcher.
   pid_t GetDexLockOwner(); // For SignalCatcher.
 
@@ -314,7 +318,6 @@
 
   Method* AllocMethod();
 
-  CodeAndDirectMethods* AllocCodeAndDirectMethods(size_t length);
   InterfaceEntry* AllocInterfaceEntry(Class* interface);
 
   Class* CreatePrimitiveClass(const char* descriptor, Primitive::Type type) {
@@ -347,6 +350,11 @@
   void LoadMethod(const DexFile& dex_file, const ClassDataItemIterator& dex_method,
                   SirtRef<Class>& klass, SirtRef<Method>& dst);
 
+  void FixupStaticTrampolines(Class* klass);
+
+  // Finds the associated oat class for a dex_file and descriptor
+  const OatFile::OatClass* GetOatClass(const DexFile& dex_file, const char* descriptor);
+
   // Attempts to insert a class into a class table.  Returns NULL if
   // the class was inserted, otherwise returns an existing class with
   // the same descriptor and ClassLoader.
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 7741d4d..1f7f24d 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -138,15 +138,15 @@
     EXPECT_TRUE(mh.GetSignature() != NULL);
 
     EXPECT_TRUE(method->GetDexCacheStrings() != NULL);
+    EXPECT_TRUE(method->GetDexCacheResolvedMethods() != NULL);
     EXPECT_TRUE(method->GetDexCacheResolvedTypes() != NULL);
-    EXPECT_TRUE(method->GetDexCacheCodeAndDirectMethods() != NULL);
     EXPECT_TRUE(method->GetDexCacheInitializedStaticStorage() != NULL);
     EXPECT_EQ(method->GetDeclaringClass()->GetDexCache()->GetStrings(),
               method->GetDexCacheStrings());
+    EXPECT_EQ(method->GetDeclaringClass()->GetDexCache()->GetResolvedMethods(),
+              method->GetDexCacheResolvedMethods());
     EXPECT_EQ(method->GetDeclaringClass()->GetDexCache()->GetResolvedTypes(),
               method->GetDexCacheResolvedTypes());
-    EXPECT_EQ(method->GetDeclaringClass()->GetDexCache()->GetCodeAndDirectMethods(),
-              method->GetDexCacheCodeAndDirectMethods());
     EXPECT_EQ(method->GetDeclaringClass()->GetDexCache()->GetInitializedStaticStorage(),
               method->GetDexCacheInitializedStaticStorage());
   }
@@ -314,6 +314,12 @@
       AssertDexFileClass(class_loader, descriptor);
     }
     class_linker_->VisitRoots(TestRootVisitor, NULL);
+    // Verify the dex cache has resolution methods in all resolved method slots
+    DexCache* dex_cache = class_linker_->FindDexCache(*dex);
+    ObjectArray<Method>* resolved_methods = dex_cache->GetResolvedMethods();
+    for (size_t i = 0; i < static_cast<size_t>(resolved_methods->GetLength()); i++) {
+      EXPECT_TRUE(resolved_methods->Get(i) != NULL);
+    }
   }
 
   static void TestRootVisitor(const Object* root, void* arg) {
@@ -441,8 +447,8 @@
   MethodOffsets() : CheckOffsets<Method>(false, "Ljava/lang/reflect/Method;") {
     // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, declaring_class_),                      "declaringClass"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_code_and_direct_methods_),    "dexCacheCodeAndDirectMethods"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_initialized_static_storage_), "dexCacheInitializedStaticStorage"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_methods_),           "dexCacheResolvedMethods"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_types_),             "dexCacheResolvedTypes"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_strings_),                    "dexCacheStrings"));
 
diff --git a/src/common_test.h b/src/common_test.h
index f487f05..7083b8c 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -332,6 +332,9 @@
             Compiler::CreateResolutionStub(instruction_set, type), type);
       }
     }
+    if (!runtime_->HasResolutionMethod()) {
+      runtime_->SetResolutionMethod(runtime_->CreateResolutionMethod());
+    }
     for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
       Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
       if (!runtime_->HasCalleeSaveMethod(type)) {
@@ -339,6 +342,7 @@
             runtime_->CreateCalleeSaveMethod(instruction_set, type), type);
       }
     }
+    class_linker_->FixupDexCaches(runtime_->GetResolutionMethod());
     compiler_.reset(new Compiler(instruction_set, false, 2, false, NULL));
 
     Heap::VerifyHeap();  // Check for heap corruption before the test
diff --git a/src/compiler.cc b/src/compiler.cc
index 75f7484..34ef0e3 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -341,7 +341,6 @@
 #if defined(ART_USE_LLVM_COMPILER)
   compiler_llvm_->MaterializeLLVMModule();
 #endif
-  SetCodeAndDirectMethods(dex_files);
 }
 
 bool Compiler::IsImageClass(const std::string& descriptor) const {
@@ -1127,30 +1126,4 @@
   compiled_method->SetGcMap(*gc_map);
 }
 
-void Compiler::SetCodeAndDirectMethods(const std::vector<const DexFile*>& dex_files) {
-  for (size_t i = 0; i != dex_files.size(); ++i) {
-    const DexFile* dex_file = dex_files[i];
-    CHECK(dex_file != NULL);
-    SetCodeAndDirectMethodsDexFile(*dex_file);
-  }
-}
-
-void Compiler::SetCodeAndDirectMethodsDexFile(const DexFile& dex_file) {
-  Runtime* runtime = Runtime::Current();
-  ClassLinker* class_linker = runtime->GetClassLinker();
-  DexCache* dex_cache = class_linker->FindDexCache(dex_file);
-  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->IsDirect()) {
-      Runtime::TrampolineType type = Runtime::GetTrampolineType(method);
-      ByteArray* res_trampoline = runtime->GetResolutionStubArray(type);
-      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.
-    }
-  }
-}
-
 }  // namespace art
diff --git a/src/compiler.h b/src/compiler.h
index b889a32..92329f0 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -163,11 +163,6 @@
   void SetGcMapsDexFile(const ClassLoader* class_loader, const DexFile& dex_file);
   void SetGcMapsMethod(const DexFile& dex_file, Method* method);
 
-  // After compiling, walk all the DexCaches and set the code and
-  // method pointers of CodeAndDirectMethods entries in the DexCaches.
-  void SetCodeAndDirectMethods(const std::vector<const DexFile*>& dex_files);
-  void SetCodeAndDirectMethodsDexFile(const DexFile& dex_file);
-
   void InsertInvokeStub(bool is_static, const char* shorty,
                         const CompiledInvokeStub* compiled_invoke_stub);
 
diff --git a/src/compiler/codegen/arm/ArchFactory.cc b/src/compiler/codegen/arm/ArchFactory.cc
index 62e4b3e..79a62ad 100644
--- a/src/compiler/codegen/arm/ArchFactory.cc
+++ b/src/compiler/codegen/arm/ArchFactory.cc
@@ -490,16 +490,17 @@
         case 0:  // Get the current Method* [sets r0]
             loadCurrMethodDirect(cUnit, r0);
             break;
-        case 1:  // Get method->code_and_direct_methods_
+        case 1:  // Get method->dex_cache_resolved_methods_
             loadWordDisp(cUnit, r0,
-                Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
+                Method::DexCacheResolvedMethodsOffset().Int32Value(),
                 r0);
             break;
-        case 2:  // Grab target method* and target code_
+        case 2:  // Grab target method*
             loadWordDisp(cUnit, r0,
-                CodeAndDirectMethods::CodeOffsetInBytes(dexIdx), rLR);
-            loadWordDisp(cUnit, r0,
-                CodeAndDirectMethods::MethodOffsetInBytes(dexIdx), r0);
+                Array::DataOffset().Int32Value() + dexIdx * 4, r0);
+            break;
+        case 3:  // Grab the code from the method*
+            loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
             break;
         default:
             return -1;
diff --git a/src/compiler_test.cc b/src/compiler_test.cc
index a7c2691..417d352 100644
--- a/src/compiler_test.cc
+++ b/src/compiler_test.cc
@@ -123,19 +123,6 @@
   // TODO check Class::IsVerified for all classes
 
   // TODO: check that all Method::GetCode() values are non-null
-
-  EXPECT_EQ(dex->NumMethodIds(), dex_cache->NumCodeAndDirectMethods());
-  CodeAndDirectMethods* code_and_direct_methods = dex_cache->GetCodeAndDirectMethods();
-  for (size_t i = 0; i < dex_cache->NumCodeAndDirectMethods(); i++) {
-    Method* method = dex_cache->GetResolvedMethod(i);
-    if (method->IsDirect()) {
-      EXPECT_EQ(method->GetCode(), code_and_direct_methods->GetResolvedCode(i));
-      EXPECT_EQ(method,            code_and_direct_methods->GetResolvedMethod(i));
-    } else {
-      EXPECT_EQ(0U, code_and_direct_methods->GetResolvedCode(i));
-      EXPECT_TRUE(code_and_direct_methods->GetResolvedMethod(i) == NULL);
-    }
-  }
 }
 
 TEST_F(CompilerTest, AbstractMethodErrorStub) {
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 7f4a132..9d334ba 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -274,12 +274,16 @@
         runtime->SetResolutionStubArray(Compiler::CreateResolutionStub(instruction_set_, type), type);
       }
     }
+    if (!runtime->HasResolutionMethod()) {
+      runtime->SetResolutionMethod(runtime->CreateResolutionMethod());
+    }
     for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
       Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
       if (!runtime->HasCalleeSaveMethod(type)) {
         runtime->SetCalleeSaveMethod(runtime->CreateCalleeSaveMethod(instruction_set_, type), type);
       }
     }
+    runtime->GetClassLinker()->FixupDexCaches(runtime->GetResolutionMethod());
     return runtime;
   }
 
diff --git a/src/dex_cache.cc b/src/dex_cache.cc
index 27f7919..02a8a55 100644
--- a/src/dex_cache.cc
+++ b/src/dex_cache.cc
@@ -23,48 +23,44 @@
 
 namespace art {
 
-void CodeAndDirectMethods::SetResolvedDirectMethodTraceEntry(uint32_t method_idx, const void* pcode) {
-  CHECK(pcode != NULL);
-  int32_t code = reinterpret_cast<int32_t>(pcode);
-  Set(CodeIndex(method_idx), code);
-}
-
-void CodeAndDirectMethods::SetResolvedDirectMethod(uint32_t method_idx, Method* method) {
-  CHECK(method != NULL);
-  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));
-}
-
 void DexCache::Init(String* location,
                     ObjectArray<String>* strings,
                     ObjectArray<Class>* resolved_types,
                     ObjectArray<Method>* resolved_methods,
                     ObjectArray<Field>* resolved_fields,
-                    CodeAndDirectMethods* code_and_direct_methods,
                     ObjectArray<StaticStorageBase>* initialized_static_storage) {
   CHECK(location != NULL);
   CHECK(strings != NULL);
   CHECK(resolved_types != NULL);
   CHECK(resolved_methods != NULL);
   CHECK(resolved_fields != NULL);
-  CHECK(code_and_direct_methods != NULL);
   CHECK(initialized_static_storage != NULL);
   Set(kLocation,                 location);
   Set(kStrings,                  strings);
   Set(kResolvedTypes,            resolved_types);
   Set(kResolvedMethods,          resolved_methods);
   Set(kResolvedFields,           resolved_fields);
-  Set(kCodeAndDirectMethods,     code_and_direct_methods);
   Set(kInitializedStaticStorage, initialized_static_storage);
 
   Runtime* runtime = Runtime::Current();
-  if (runtime->IsStarted()) {
-    Runtime::TrampolineType unknown_method_resolution_type = Runtime::GetTrampolineType(NULL);
-    ByteArray* res_trampoline = runtime->GetResolutionStubArray(unknown_method_resolution_type);
-    for (size_t i = 0; i < NumResolvedMethods(); i++) {
-      code_and_direct_methods->SetResolvedDirectMethodTrampoline(i, res_trampoline);
+  if (runtime->HasResolutionMethod()) {
+    // Initialize the resolve methods array to contain trampolines for resolution.
+    Method* trampoline = runtime->GetResolutionMethod();
+    size_t length = resolved_methods->GetLength();
+    for (size_t i = 0; i < length; i++) {
+      resolved_methods->SetWithoutChecks(i, trampoline);
+    }
+  }
+}
+
+void DexCache::Fixup(Method* trampoline) {
+  // Fixup the resolve methods array to contain trampoline for resolution.
+  CHECK(trampoline != NULL);
+  ObjectArray<Method>* resolved_methods = down_cast<ObjectArray<Method>*>(Get(kResolvedMethods));
+  size_t length = resolved_methods->GetLength();
+  for (size_t i = 0; i < length; i++) {
+    if (resolved_methods->GetWithoutChecks(i) == NULL) {
+      resolved_methods->SetWithoutChecks(i, trampoline);
     }
   }
 }
diff --git a/src/dex_cache.h b/src/dex_cache.h
index f748e57..2aa2a6a 100644
--- a/src/dex_cache.h
+++ b/src/dex_cache.h
@@ -31,64 +31,6 @@
 class String;
 union JValue;
 
-class MANAGED CodeAndDirectMethods : public IntArray {
- public:
-  void* GetResolvedCode(uint32_t method_idx) const {
-    return reinterpret_cast<byte*>(Get(CodeIndex(method_idx)));
-  }
-  Method* GetResolvedMethod(uint32_t method_idx) const {
-    return reinterpret_cast<Method*>(Get(MethodIndex(method_idx)));
-  }
-
-  void SetResolvedDirectMethodTrampoline(uint32_t method_idx, ByteArray* code_array) {
-    CHECK(code_array != NULL);
-    int32_t code = reinterpret_cast<int32_t>(code_array->GetData());
-    Set(CodeIndex(method_idx), code);
-    Set(MethodIndex(method_idx), method_idx);
-  }
-
-  void SetResolvedDirectMethodTraceEntry(uint32_t method_idx, const void* pcode);
-
-  void SetResolvedDirectMethod(uint32_t method_idx, Method* method);
-
-  static size_t LengthAsArray(size_t elements) {
-    return kMax * elements;
-  }
-
-  // Offset of resolved method entry from start of code_and_direct_methods_
-  static size_t MethodOffsetInBytes(uint32_t method_idx) {
-    return (MethodIndex(method_idx) * sizeof(ElementType) + Array::DataOffset().Int32Value());
-  }
-
-  // Offset of resolved method's code_ from start of code_and_direct_methods_
-  static size_t CodeOffsetInBytes(uint32_t method_idx) {
-    return (CodeIndex(method_idx) * sizeof(ElementType) + Array::DataOffset().Int32Value());
-  }
-
-  size_t NumCodeAndDirectMethods() const {
-    return GetLength() / kMax;
-  }
-
-  static size_t CodeIndex(uint32_t method_idx) {
-    return method_idx * kMax + kCode;
-  }
-  static size_t MethodIndex(uint32_t method_idx) {
-    return method_idx * kMax + kMethod;
-  }
-
- private:
-  enum TupleIndex {
-    kCode   = 0,
-    kMethod = 1,
-    kMax    = 2,
-  };
-
-  // grant friend status to ImageWriter fixup code that needs to know internal layout
-  friend class ImageWriter;
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(CodeAndDirectMethods);
-};
-
 class MANAGED DexCache : public ObjectArray<Object> {
  public:
   void Init(String* location,
@@ -96,9 +38,10 @@
             ObjectArray<Class>* types,
             ObjectArray<Method>* methods,
             ObjectArray<Field>* fields,
-            CodeAndDirectMethods* code_and_direct_methods,
             ObjectArray<StaticStorageBase>* initialized_static_storage);
 
+  void Fixup(Method* trampoline);
+
   String* GetLocation() const {
     return Get(kLocation)->AsString();
   }
@@ -134,10 +77,6 @@
     return GetResolvedFields()->GetLength();
   }
 
-  size_t NumCodeAndDirectMethods() const {
-    return GetCodeAndDirectMethods()->NumCodeAndDirectMethods();
-  }
-
   size_t NumInitializedStaticStorage() const {
     return GetInitializedStaticStorage()->GetLength();
   }
@@ -159,7 +98,14 @@
   }
 
   Method* GetResolvedMethod(uint32_t method_idx) const {
-    return GetResolvedMethods()->Get(method_idx);
+    Method* method = GetResolvedMethods()->Get(method_idx);
+    // Hide resolution trampoline methods from the caller
+    if (method != NULL && method->GetDexMethodIndex() == DexFile::kDexNoIndex16) {
+      DCHECK(method == Runtime::Current()->GetResolutionMethod());
+      return NULL;
+    } else {
+      return method;
+    }
   }
 
   void SetResolvedMethod(uint32_t method_idx, Method* resolved) {
@@ -186,9 +132,6 @@
   ObjectArray<Field>* GetResolvedFields() const {
     return static_cast<ObjectArray<Field>*>(GetNonNull(kResolvedFields));
   }
-  CodeAndDirectMethods* GetCodeAndDirectMethods() const {
-    return static_cast<CodeAndDirectMethods*>(GetNonNull(kCodeAndDirectMethods));
-  }
   ObjectArray<StaticStorageBase>* GetInitializedStaticStorage() const {
     return static_cast<ObjectArray<StaticStorageBase>*>(GetNonNull(kInitializedStaticStorage));
   }
@@ -205,9 +148,8 @@
     kResolvedTypes            = 2,
     kResolvedMethods          = 3,
     kResolvedFields           = 4,
-    kCodeAndDirectMethods     = 5,
-    kInitializedStaticStorage = 6,
-    kMax                      = 7,
+    kInitializedStaticStorage = 5,
+    kMax                      = 6,
   };
 
   Object* GetNonNull(ArrayIndex array_index) const {
diff --git a/src/dex_cache_test.cc b/src/dex_cache_test.cc
index c8dbc7c..6340d79 100644
--- a/src/dex_cache_test.cc
+++ b/src/dex_cache_test.cc
@@ -34,14 +34,12 @@
   EXPECT_EQ(java_lang_dex_file_->NumTypeIds(),   dex_cache->NumResolvedTypes());
   EXPECT_EQ(java_lang_dex_file_->NumMethodIds(), dex_cache->NumResolvedMethods());
   EXPECT_EQ(java_lang_dex_file_->NumFieldIds(),  dex_cache->NumResolvedFields());
-  EXPECT_EQ(java_lang_dex_file_->NumMethodIds(), dex_cache->NumCodeAndDirectMethods());
   EXPECT_EQ(java_lang_dex_file_->NumTypeIds(),   dex_cache->NumInitializedStaticStorage());
 
   EXPECT_LE(0, dex_cache->GetStrings()->GetLength());
   EXPECT_LE(0, dex_cache->GetResolvedTypes()->GetLength());
   EXPECT_LE(0, dex_cache->GetResolvedMethods()->GetLength());
   EXPECT_LE(0, dex_cache->GetResolvedFields()->GetLength());
-  EXPECT_LE(0, dex_cache->GetCodeAndDirectMethods()->GetLength());
   EXPECT_LE(0, dex_cache->GetInitializedStaticStorage()->GetLength());
 
   EXPECT_EQ(java_lang_dex_file_->NumStringIds(),
@@ -52,8 +50,6 @@
             static_cast<uint32_t>(dex_cache->GetResolvedMethods()->GetLength()));
   EXPECT_EQ(java_lang_dex_file_->NumFieldIds(),
             static_cast<uint32_t>(dex_cache->GetResolvedFields()->GetLength()));
-  EXPECT_EQ(java_lang_dex_file_->NumMethodIds(),
-            static_cast<uint32_t>(dex_cache->GetCodeAndDirectMethods()->NumCodeAndDirectMethods()));
   EXPECT_EQ(java_lang_dex_file_->NumTypeIds(),
             static_cast<uint32_t>(dex_cache->GetInitializedStaticStorage()->GetLength()));
 }
diff --git a/src/image.h b/src/image.h
index 1b80cb6..a709c1b 100644
--- a/src/image.h
+++ b/src/image.h
@@ -85,6 +85,7 @@
     kInstanceResolutionStubArray,
     kStaticResolutionStubArray,
     kUnknownMethodResolutionStubArray,
+    kResolutionMethod,
     kCalleeSaveMethod,
     kRefsOnlySaveMethod,
     kRefsAndArgsSaveMethod,
diff --git a/src/image_writer.cc b/src/image_writer.cc
index 59d113d..611dce1 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -115,6 +115,7 @@
   Runtime* runtime = Runtime::Current();
   ClassLinker* class_linker = runtime->GetClassLinker();
   class_linker->VisitClasses(ComputeLazyFieldsForClassesVisitor, NULL);
+
 }
 
 bool ImageWriter::ComputeLazyFieldsForClassesVisitor(Class* klass, void* arg) {
@@ -189,6 +190,7 @@
     class_linker->RemoveClass((*it).c_str(), NULL);
   }
 
+  Method* resolution_method = runtime->GetResolutionMethod();
   typedef Set::const_iterator CacheIt;  // TODO: C++0x auto
   for (CacheIt it = dex_caches_.begin(), end = dex_caches_.end(); it != end; ++it) {
     DexCache* dex_cache = *it;
@@ -202,10 +204,7 @@
     for (size_t i = 0; i < dex_cache->NumResolvedMethods(); i++) {
       Method* method = dex_cache->GetResolvedMethod(i);
       if (method != NULL && !IsImageClass(method->GetDeclaringClass())) {
-        dex_cache->SetResolvedMethod(i, NULL);
-        Runtime::TrampolineType type = Runtime::GetTrampolineType(method);
-        ByteArray* res_trampoline = runtime->GetResolutionStubArray(type);
-        dex_cache->GetCodeAndDirectMethods()->SetResolvedDirectMethodTrampoline(i, res_trampoline);
+        dex_cache->SetResolvedMethod(i, resolution_method);
       }
     }
     for (size_t i = 0; i < dex_cache->NumResolvedFields(); i++) {
@@ -309,6 +308,7 @@
                    runtime->GetResolutionStubArray(Runtime::kStaticMethod));
   image_roots->Set(ImageHeader::kUnknownMethodResolutionStubArray,
                    runtime->GetResolutionStubArray(Runtime::kUnknownMethod));
+  image_roots->Set(ImageHeader::kResolutionMethod, runtime->GetResolutionMethod());
   image_roots->Set(ImageHeader::kCalleeSaveMethod,
                    runtime->GetCalleeSaveMethod(Runtime::kSaveAll));
   image_roots->Set(ImageHeader::kRefsOnlySaveMethod,
@@ -360,7 +360,6 @@
   // TODO: heap validation can't handle this fix up pass
   Heap::DisableObjectValidation();
   heap_bitmap->Walk(CopyAndFixupObjectsCallback, this);  // TODO: add Space-limited Walk
-  FixupDexCaches();
 }
 
 void ImageWriter::CopyAndFixupObjectsCallback(Object* object, void* arg) {
@@ -405,19 +404,6 @@
   FixupStaticFields(orig, copy);
 }
 
-static uint32_t FixupCode(const ByteArray* copy_code_array, uint32_t orig_code) {
-  // TODO: change to DCHECK when all code compiling
-  if (copy_code_array == NULL) {
-    return 0;
-  }
-  uint32_t copy_code = reinterpret_cast<uint32_t>(copy_code_array->GetData());
-  // TODO: remember InstructionSet with each code array so we know if we need to do thumb fixup?
-  if ((orig_code % 2) == 1) {
-    return copy_code + 1;
-  }
-  return copy_code;
-}
-
 void ImageWriter::FixupMethod(const Method* orig, Method* copy) {
   FixupInstanceFields(orig, copy);
 
@@ -437,9 +423,31 @@
     return;
   }
 
+  if (orig == Runtime::Current()->GetResolutionMethod()) {
+    // The resolution stub's code points at the unknown resolution trampoline
+    ByteArray* orig_res_stub_array_ =
+        Runtime::Current()->GetResolutionStubArray(Runtime::kUnknownMethod);
+    CHECK(orig->GetCode() == orig_res_stub_array_->GetData());
+    ByteArray* copy_res_stub_array_ = down_cast<ByteArray*>(GetImageAddress(orig_res_stub_array_));
+    copy->code_ = copy_res_stub_array_->GetData();
+    return;
+  }
+
   // Non-abstract methods typically have code
   uint32_t code_offset = orig->GetOatCodeOffset();
-  const byte* code = GetOatAddress(code_offset);
+  const byte* code = NULL;
+  if (orig->IsStatic()) {
+    // Static methods may point at the resolution trampoline stub
+    ByteArray* orig_res_stub_array_ =
+        Runtime::Current()->GetResolutionStubArray(Runtime::kStaticMethod);
+    if (reinterpret_cast<int8_t*>(code_offset) == orig_res_stub_array_->GetData()) {
+      ByteArray* copy_res_stub_array_ = down_cast<ByteArray*>(GetImageAddress(orig_res_stub_array_));
+      code = reinterpret_cast<const byte*>(copy_res_stub_array_->GetData());
+    }
+  }
+  if (code == NULL) {
+    code = GetOatAddress(code_offset);
+  }
   copy->code_ = code;
 
   if (orig->IsNative()) {
@@ -460,6 +468,7 @@
 
     uint32_t gc_map_offset = orig->GetOatGcMapOffset();
     const byte* gc_map = GetOatAddress(gc_map_offset);
+    CHECK(gc_map != NULL || orig->IsRuntimeMethod()) << PrettyMethod(orig);
     copy->gc_map_ = reinterpret_cast<const uint8_t*>(gc_map);
   }
 }
@@ -527,58 +536,4 @@
   }
 }
 
-void ImageWriter::FixupDexCaches() {
-  typedef Set::const_iterator It;  // TODO: C++0x auto
-  for (It it = dex_caches_.begin(), end = dex_caches_.end(); it != end; ++it) {
-    DexCache* orig = *it;
-    DexCache* copy = down_cast<DexCache*>(GetLocalAddress(orig));
-    FixupDexCache(orig, copy);
-  }
-}
-
-void ImageWriter::FixupDexCache(const DexCache* orig, DexCache* copy) {
-  CHECK(orig != NULL);
-  CHECK(copy != NULL);
-
-  // The original array value
-  CodeAndDirectMethods* orig_cadms = orig->GetCodeAndDirectMethods();
-  // The compacted object in local memory but not at the correct image address
-  CodeAndDirectMethods* copy_cadms = down_cast<CodeAndDirectMethods*>(GetLocalAddress(orig_cadms));
-
-  Runtime* runtime = Runtime::Current();
-  for (size_t i = 0; i < orig->NumResolvedMethods(); i++) {
-    Method* orig_method = orig->GetResolvedMethod(i);
-    if (orig_method != NULL && !InSourceSpace(orig_method)) {
-      continue;
-    }
-    // if it was unresolved or a resolved static method in an uninit class, use a resolution stub
-    // we need to use the stub in the static method case to ensure <clinit> is run.
-    if (orig_method == NULL
-        || (orig_method->IsStatic() && !orig_method->GetDeclaringClass()->IsInitialized())) {
-      uint32_t orig_res_stub_code = orig_cadms->Get(CodeAndDirectMethods::CodeIndex(i));
-      if (orig_res_stub_code == 0) {
-        continue;  // NULL maps the same in the image and the original
-      }
-      Runtime::TrampolineType type = Runtime::GetTrampolineType(orig_method);  // Type of trampoline
-      ByteArray* orig_res_stub_array = runtime->GetResolutionStubArray(type);
-      // Do we need to relocate this for this space?
-      if (!InSourceSpace(orig_res_stub_array)) {
-        continue;
-      }
-      // Compute address in image of resolution stub and the code address
-      ByteArray* image_res_stub_array = down_cast<ByteArray*>(GetImageAddress(orig_res_stub_array));
-      uint32_t image_res_stub_code = FixupCode(image_res_stub_array, orig_res_stub_code);
-      // Put the image code address in the array
-      copy_cadms->Set(CodeAndDirectMethods::CodeIndex(i), image_res_stub_code);
-    } else if (orig_method->IsDirect()) {
-      // if it was resolved in the original, resolve it in the copy
-      Method* copy_method = down_cast<Method*>(GetLocalAddress(orig_method));
-      copy_cadms->Set(CodeAndDirectMethods::CodeIndex(i),
-                      reinterpret_cast<int32_t>(copy_method->code_));
-      copy_cadms->Set(CodeAndDirectMethods::MethodIndex(i),
-                      reinterpret_cast<int32_t>(GetImageAddress(orig_method)));
-    }
-  }
-}
-
 }  // namespace art
diff --git a/src/image_writer.h b/src/image_writer.h
index 8db3570..9d46c06 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -134,9 +134,6 @@
   void FixupStaticFields(const Class* orig, Class* copy);
   void FixupFields(const Object* orig, Object* copy, uint32_t ref_offsets, bool is_static);
 
-  void FixupDexCaches();
-  void FixupDexCache(const DexCache* orig, DexCache* copy);
-
   // oat file with code for this image
   UniquePtr<OatFile> oat_file_;
 
diff --git a/src/java_lang_reflect_Method.cc b/src/java_lang_reflect_Method.cc
index b32f815..7049eff 100644
--- a/src/java_lang_reflect_Method.cc
+++ b/src/java_lang_reflect_Method.cc
@@ -50,7 +50,7 @@
   return AddLocalReference<jobject>(env, declared_exceptions->Clone());
 }
 
-jobject Method_findOverriddenMethod(JNIEnv* env, jobject javaMethod) {
+jobject Method_findOverriddenMethodNative(JNIEnv* env, jobject javaMethod) {
   Method* method = Decode<Object*>(env, javaMethod)->AsMethod();
   return AddLocalReference<jobject>(env, method->FindOverriddenMethod());
 }
@@ -58,7 +58,7 @@
 static JNINativeMethod gMethods[] = {
   NATIVE_METHOD(Method, invoke, "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"),
   NATIVE_METHOD(Method, getExceptionTypesNative, "()[Ljava/lang/Class;"),
-  NATIVE_METHOD(Method, findOverriddenMethod, "()Ljava/lang/reflect/Method;"),
+  NATIVE_METHOD(Method, findOverriddenMethodNative, "()Ljava/lang/reflect/Method;"),
 };
 
 }  // namespace
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index d0a6776..60e34ba 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -2266,13 +2266,13 @@
     for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
       Method* m = c->GetDirectMethod(i);
       if (m->IsNative()) {
-        m->UnregisterNative();
+        m->UnregisterNative(ts.Self());
       }
     }
     for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
       Method* m = c->GetVirtualMethod(i);
       if (m->IsNative()) {
-        m->UnregisterNative();
+        m->UnregisterNative(ts.Self());
       }
     }
 
diff --git a/src/oat_file.cc b/src/oat_file.cc
index 26314b1..22dc92c 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -278,7 +278,7 @@
   method->SetFpSpillMask(fp_spill_mask_);
   method->SetMappingTable(GetMappingTable());
   method->SetVmapTable(GetVmapTable());
-  method->SetGcMap(GetGcMap());
+  method->SetGcMap(GetGcMap());  // Note, used by native methods in work around JNI mode.
   method->SetInvokeStub(GetInvokeStub());
 }
 
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index e4c8135..99c42f7 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -340,7 +340,13 @@
     method->SetCoreSpillMask(core_spill_mask);
     method->SetFpSpillMask(fp_spill_mask);
     method->SetOatMappingTableOffset(mapping_table_offset);
-    method->SetOatCodeOffset(code_offset);
+    // Don't overwrite static method trampoline
+    if (!method->IsStatic() || method->IsConstructor() ||
+        method->GetDeclaringClass()->IsInitialized()) {
+      method->SetOatCodeOffset(code_offset);
+    } else {
+      method->SetCode(Runtime::Current()->GetResolutionStubArray(Runtime::kStaticMethod)->GetData());
+    }
     method->SetOatVmapTableOffset(vmap_table_offset);
     method->SetOatGcMapOffset(gc_map_offset);
     method->SetOatInvokeStubOffset(invoke_stub_offset);
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 1bbbb08..7c9fa92 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -70,6 +70,7 @@
   "kInstanceResolutionStubArray",
   "kStaticResolutionStubArray",
   "kUnknownMethodResolutionStubArray",
+  "kResolutionMethod",
   "kCalleeSaveMethod",
   "kRefsOnlySaveMethod",
   "kRefsAndArgsSaveMethod",
@@ -428,7 +429,8 @@
         DCHECK(method->GetGcMap() == NULL) << PrettyMethod(method);
         DCHECK_EQ(0U, method->GetGcMapLength()) << PrettyMethod(method);
         DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
-      } else if (method->IsAbstract() || method->IsCalleeSaveMethod()) {
+      } else if (method->IsAbstract() || method->IsCalleeSaveMethod() ||
+          method->IsResolutionMethod()) {
         DCHECK(method->GetGcMap() == NULL) << PrettyMethod(method);
         DCHECK_EQ(0U, method->GetGcMapLength()) << PrettyMethod(method);
         DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
diff --git a/src/object.cc b/src/object.cc
index cf15a64..7217549 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -351,6 +351,16 @@
                  new_dex_cache_strings, false);
 }
 
+ObjectArray<Method>* Method::GetDexCacheResolvedMethods() const {
+  return GetFieldObject<ObjectArray<Method>*>(
+      OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_resolved_methods_), false);
+}
+
+void Method::SetDexCacheResolvedMethods(ObjectArray<Method>* new_dex_cache_methods) {
+  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_resolved_methods_),
+                 new_dex_cache_methods, false);
+}
+
 ObjectArray<Class>* Method::GetDexCacheResolvedTypes() const {
   return GetFieldObject<ObjectArray<Class>*>(
       OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_resolved_types_), false);
@@ -361,18 +371,6 @@
                  new_dex_cache_classes, false);
 }
 
-CodeAndDirectMethods* Method::GetDexCacheCodeAndDirectMethods() const {
-  return GetFieldPtr<CodeAndDirectMethods*>(
-      OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_code_and_direct_methods_),
-      false);
-}
-
-void Method::SetDexCacheCodeAndDirectMethods(CodeAndDirectMethods* new_value) {
-  SetFieldPtr<CodeAndDirectMethods*>(
-      OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_code_and_direct_methods_),
-      new_value, false);
-}
-
 ObjectArray<StaticStorageBase>* Method::GetDexCacheInitializedStaticStorage() const {
   return GetFieldObject<ObjectArray<StaticStorageBase>*>(
       OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_initialized_static_storage_),
@@ -447,7 +445,9 @@
   } else {
     // Method didn't override superclass method so search interfaces
     if (IsProxyMethod()) {
-      result = Runtime::Current()->GetClassLinker()->FindMethodForProxy(GetDeclaringClass(), this);
+      result = GetDexCacheResolvedMethods()->Get(GetDexMethodIndex());
+      CHECK_EQ(result,
+               Runtime::Current()->GetClassLinker()->FindMethodForProxy(GetDeclaringClass(), this));
     } else {
       MethodHelper mh(this);
       MethodHelper interface_mh;
@@ -481,12 +481,17 @@
   }
   size_t mapping_table_length = GetMappingTableLength();
   const void* code_offset;
-  if (Runtime::Current()->IsMethodTracingActive() &&
-      Runtime::Current()->GetTracer()->GetSavedCodeFromMap(this) != NULL) {
-    code_offset = Runtime::Current()->GetTracer()->GetSavedCodeFromMap(this);
+  Runtime* runtime = Runtime::Current();
+  if (runtime->IsMethodTracingActive() &&
+      runtime->GetTracer()->GetSavedCodeFromMap(this) != NULL) {
+    code_offset = runtime->GetTracer()->GetSavedCodeFromMap(this);
   } else {
     code_offset = GetCode();
   }
+  if (code_offset == runtime->GetResolutionStubArray(Runtime::kStaticMethod)->GetData() ||
+      code_offset == runtime->GetResolutionStubArray(Runtime::kInstanceMethod)->GetData()) {
+    code_offset = runtime->GetClassLinker()->GetOatCodeFor(this);
+  }
   uint32_t sought_offset = pc - reinterpret_cast<uintptr_t>(code_offset);
   uint32_t best_offset = 0;
   uint32_t best_dex_offset = 0;
@@ -595,6 +600,7 @@
 
 bool Method::IsRegistered() const {
   void* native_method = GetFieldPtr<void*>(OFFSET_OF_OBJECT_MEMBER(Method, native_method_), false);
+  CHECK(native_method != NULL);
   void* jni_stub = Runtime::Current()->GetJniDlsymLookupStub()->GetData();
   return native_method != jni_stub;
 }
@@ -622,11 +628,10 @@
   }
 }
 
-void Method::UnregisterNative() {
+void Method::UnregisterNative(Thread* self) {
   CHECK(IsNative()) << PrettyMethod(this);
   // restore stub to lookup native pointer via dlsym
-  SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(Method, native_method_),
-      Runtime::Current()->GetJniDlsymLookupStub()->GetData(), false);
+  RegisterNative(self, Runtime::Current()->GetJniDlsymLookupStub()->GetData());
 }
 
 void Class::SetStatus(Status new_status) {
@@ -1516,11 +1521,16 @@
     // Decode the internal stack trace into the depth and method trace
     ObjectArray<Object>* method_trace = down_cast<ObjectArray<Object>*>(stack_state);
     int32_t depth = method_trace->GetLength() - 1;
+    IntArray* pc_trace = down_cast<IntArray*>(method_trace->Get(depth));
+    MethodHelper mh;
     for (int32_t i = 0; i < depth; ++i) {
       Method* method = down_cast<Method*>(method_trace->Get(i));
-      result += "  at ";
-      result += PrettyMethod(method, true);
-      result += "\n";
+      mh.ChangeMethod(method);
+      uint32_t native_pc = pc_trace->Get(i);
+      int32_t line_number = mh.GetLineNumFromNativePC(native_pc);
+      const char* source_file = mh.GetDeclaringClassSourceFile();
+      result += StringPrintf("  at %s (%s:%d)\n", PrettyMethod(method, true).c_str(),
+                             source_file, line_number);
     }
   }
   Throwable* cause = GetFieldObject<Throwable*>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_), false);
diff --git a/src/object.h b/src/object.h
index da8064f..29d8255 100644
--- a/src/object.h
+++ b/src/object.h
@@ -598,6 +598,10 @@
     return OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_strings_);
   }
 
+  static MemberOffset DexCacheResolvedMethodsOffset() {
+    return OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_resolved_methods_);
+  }
+
   static MemberOffset DexCacheResolvedTypesOffset() {
     return OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_resolved_types_);
   }
@@ -607,12 +611,12 @@
         dex_cache_initialized_static_storage_);
   }
 
+  ObjectArray<Method>* GetDexCacheResolvedMethods() const;
+  void SetDexCacheResolvedMethods(ObjectArray<Method>* new_dex_cache_methods);
+
   ObjectArray<Class>* GetDexCacheResolvedTypes() const;
   void SetDexCacheResolvedTypes(ObjectArray<Class>* new_dex_cache_types);
 
-  CodeAndDirectMethods* GetDexCacheCodeAndDirectMethods() const;
-  void SetDexCacheCodeAndDirectMethods(CodeAndDirectMethods* new_value);
-
   ObjectArray<StaticStorageBase>* GetDexCacheInitializedStaticStorage() const;
   void SetDexCacheInitializedStaticStorage(ObjectArray<StaticStorageBase>* new_value);
 
@@ -764,7 +768,7 @@
 
   void RegisterNative(Thread* self, const void* native_method);
 
-  void UnregisterNative();
+  void UnregisterNative(Thread* self);
 
   static MemberOffset NativeMethodOffset() {
     return OFFSET_OF_OBJECT_MEMBER(Method, native_method_);
@@ -801,10 +805,6 @@
     return OFFSET_OF_OBJECT_MEMBER(Method, invoke_stub_);
   }
 
-  static MemberOffset GetDexCacheCodeAndDirectMethodsOffset() {
-    return OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_code_and_direct_methods_);
-  }
-
   static MemberOffset GetMethodIndexOffset() {
     return OFFSET_OF_OBJECT_MEMBER(Method, method_index_);
   }
@@ -838,10 +838,23 @@
       }
     }
     // Check that if we do think it is phony it looks like the callee save method
-    DCHECK(!result || GetCoreSpillMask() != 0);
+    DCHECK(!result || GetDexMethodIndex() == DexFile::kDexNoIndex16);
     return result;
   }
 
+  bool IsResolutionMethod() const {
+    bool result = this == Runtime::Current()->GetResolutionMethod();
+    // Check that if we do think it is phony it looks like the resolution method
+    DCHECK(!result || GetDexMethodIndex() == DexFile::kDexNoIndex16);
+    return result;
+  }
+
+  // Is this a CalleSaveMethod or ResolutionMethod and therefore doesn't adhere to normal
+  // conventions for a method of managed code.
+  bool IsRuntimeMethod() const {
+    return GetDexMethodIndex() == DexFile::kDexNoIndex16;
+  }
+
   // Converts a native PC to a dex PC.  TODO: this is a no-op
   // until we associate a PC mapping table with each method.
   uint32_t ToDexPC(const uintptr_t pc) const;
@@ -871,10 +884,10 @@
   Class* declaring_class_;
 
   // short cuts to declaring_class_->dex_cache_ member for fast compiled code access
-  CodeAndDirectMethods* dex_cache_code_and_direct_methods_;
+  ObjectArray<StaticStorageBase>* dex_cache_initialized_static_storage_;
 
   // short cuts to declaring_class_->dex_cache_ member for fast compiled code access
-  ObjectArray<StaticStorageBase>* dex_cache_initialized_static_storage_;
+  ObjectArray<Class>* dex_cache_resolved_methods_;
 
   // short cuts to declaring_class_->dex_cache_ member for fast compiled code access
   ObjectArray<Class>* dex_cache_resolved_types_;
@@ -917,6 +930,8 @@
   //
   // For abstract methods in an interface class, this is the offset of the method in
   // "iftable_->Get(n)->GetMethodArray()".
+  //
+  // For static and direct methods this is the index in the direct methods table.
   uint32_t method_index_;
 
   // The target native method registered with this method
diff --git a/src/object_utils.h b/src/object_utils.h
index 0e0d7de..b9d8a24 100644
--- a/src/object_utils.h
+++ b/src/object_utils.h
@@ -399,11 +399,28 @@
   }
   const char* GetName() {
     const DexFile& dex_file = GetDexFile();
-    return dex_file.GetMethodName(dex_file.GetMethodId(method_->GetDexMethodIndex()));
+    uint32_t dex_method_idx = method_->GetDexMethodIndex();
+    if (dex_method_idx != DexFile::kDexNoIndex16) {
+      return dex_file.GetMethodName(dex_file.GetMethodId(dex_method_idx));
+    } else {
+      Runtime* runtime = Runtime::Current();
+      if (method_ == runtime->GetResolutionMethod()) {
+        return "<VM internal resolution method>";
+      } else if (method_ == runtime->GetCalleeSaveMethod(Runtime::kSaveAll)) {
+        return "<VM internal callee-save all registers method>";
+      } else if (method_ == runtime->GetCalleeSaveMethod(Runtime::kRefsOnly)) {
+        return "<VM internal callee-save reference registers method>";
+      } else if (method_ == runtime->GetCalleeSaveMethod(Runtime::kRefsAndArgs)) {
+        return "<VM internal callee-save reference and argument registers method>";
+      } else {
+        return "<unknown VM internal method>";
+      }
+    }
   }
   String* GetNameAsString() {
     const DexFile& dex_file = GetDexFile();
-    const DexFile::MethodId& method_id = dex_file.GetMethodId(method_->GetDexMethodIndex());
+    uint32_t dex_method_idx = method_->GetDexMethodIndex();
+    const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
     return GetClassLinker()->ResolveString(dex_file, method_id.name_idx_, GetDexCache());
   }
   const char* GetShorty() {
@@ -424,7 +441,12 @@
   }
   const std::string GetSignature() {
     const DexFile& dex_file = GetDexFile();
-    return dex_file.GetMethodSignature(dex_file.GetMethodId(method_->GetDexMethodIndex()));
+    uint32_t dex_method_idx = method_->GetDexMethodIndex();
+    if (dex_method_idx != DexFile::kDexNoIndex16) {
+      return dex_file.GetMethodSignature(dex_file.GetMethodId(dex_method_idx));
+    } else {
+      return "<no signature>";
+    }
   }
   const DexFile::ProtoId& GetPrototype() {
     const DexFile& dex_file = GetDexFile();
@@ -558,8 +580,11 @@
     if (method != NULL) {
       Class* klass = method->GetDeclaringClass();
       if (klass->IsProxyClass()) {
-        method = GetClassLinker()->FindMethodForProxy(klass, method);
-        CHECK(method != NULL);
+        Method* interface_method =
+            method->GetDexCacheResolvedMethods()->Get(method->GetDexMethodIndex());
+        CHECK(interface_method != NULL);
+        CHECK(interface_method == GetClassLinker()->FindMethodForProxy(klass, method));
+        method = interface_method;
       }
     }
     method_ = method;
diff --git a/src/runtime.cc b/src/runtime.cc
index 537aadb..f0a6bbc 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -61,6 +61,7 @@
       java_vm_(NULL),
       jni_stub_array_(NULL),
       abstract_method_error_stub_array_(NULL),
+      resolution_method_(NULL),
       system_class_loader_(NULL),
       shutting_down_(false),
       started_(false),
@@ -802,6 +803,7 @@
   for (int i = 0; i < Runtime::kLastTrampolineMethodType; i++) {
     visitor(resolution_stub_array_[i], arg);
   }
+  visitor(resolution_method_, arg);
   for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
     visitor(callee_save_method_[i], arg);
   }
@@ -865,12 +867,38 @@
   resolution_stub_array_[type] = resolution_stub_array;
 }
 
+Method* Runtime::CreateResolutionMethod() {
+  Class* method_class = Method::GetMethodClass();
+  SirtRef<Method> method(down_cast<Method*>(method_class->AllocObject()));
+  method->SetDeclaringClass(method_class);
+  // TODO: use a special method for resolution method saves
+  method->SetDexMethodIndex(DexFile::kDexNoIndex16);
+  ByteArray* unknown_resolution_stub = GetResolutionStubArray(kUnknownMethod);
+  CHECK(unknown_resolution_stub != NULL);
+  method->SetCode(unknown_resolution_stub->GetData());
+  return method.get();
+}
+
+bool Runtime::HasResolutionMethod() const {
+  return resolution_method_ != NULL;
+}
+
+// Returns a special method that calls into a trampoline for runtime method resolution
+Method* Runtime::GetResolutionMethod() const {
+  CHECK(HasResolutionMethod());
+  return resolution_method_;
+}
+
+void Runtime::SetResolutionMethod(Method* method) {
+  resolution_method_ = method;
+}
+
 Method* Runtime::CreateCalleeSaveMethod(InstructionSet instruction_set, CalleeSaveType type) {
   Class* method_class = Method::GetMethodClass();
   SirtRef<Method> method(down_cast<Method*>(method_class->AllocObject()));
   method->SetDeclaringClass(method_class);
   // TODO: use a special method for callee saves
-  method->SetMethodIndex(DexFile::kDexNoIndex16);
+  method->SetDexMethodIndex(DexFile::kDexNoIndex16);
   method->SetCode(NULL);
   if ((instruction_set == kThumb2) || (instruction_set == kArm)) {
     uint32_t ref_spills = (1 << art::arm::R5) | (1 << art::arm::R6)  | (1 << art::arm::R7) |
diff --git a/src/runtime.h b/src/runtime.h
index af44948..fb1cd03 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -193,6 +193,12 @@
   ByteArray* GetResolutionStubArray(TrampolineType type) const;
   void SetResolutionStubArray(ByteArray* resolution_stub_array, TrampolineType type);
 
+  // Returns a special method to trampoline into runtime resolution
+  Method* CreateResolutionMethod();
+  bool HasResolutionMethod() const;
+  Method* GetResolutionMethod() const;
+  void SetResolutionMethod(Method* method);
+
   // Returns a special method that describes all callee saves being spilled to the stack.
   enum CalleeSaveType {
     kSaveAll,
@@ -284,6 +290,8 @@
 
   Method* callee_save_method_[kLastCalleeSaveType];
 
+  Method* resolution_method_;
+
   // As returned by ClassLoader.getSystemClassLoader()
   ClassLoader* system_class_loader_;
 
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 8dd7eed..00c58b5 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -388,8 +388,8 @@
   thread->DeliverException();
 }
 
-void* UnresolvedDirectMethodTrampolineFromCode(int32_t method_idx, Method** sp, Thread* thread,
-                                               Runtime::TrampolineType type) {
+const void* UnresolvedDirectMethodTrampolineFromCode(Method* called, Method** sp, Thread* thread,
+                                                     Runtime::TrampolineType type) {
   // TODO: this code is specific to ARM
   // On entry the stack pointed by sp is:
   // | argN       |  |
@@ -414,22 +414,16 @@
   // Start new JNI local reference state
   JNIEnvExt* env = thread->GetJniEnv();
   ScopedJniEnvLocalRefState env_state(env);
-  // Discover shorty (avoid GCs)
+
+  // Compute details about the called method (avoid GCs)
   ClassLinker* linker = Runtime::Current()->GetClassLinker();
-  const char* shorty = linker->MethodShorty(method_idx, *caller_sp);
-  size_t shorty_len = strlen(shorty);
-  size_t args_in_regs = 0;
-  for (size_t i = 1; i < shorty_len; i++) {
-    char c = shorty[i];
-    args_in_regs = args_in_regs + (c == 'J' || c == 'D' ? 2 : 1);
-    if (args_in_regs > 3) {
-      args_in_regs = 3;
-      break;
-    }
-  }
+  Method* caller = *caller_sp;
   bool is_static;
+  uint32_t dex_method_idx;
+  const char* shorty;
+  uint32_t shorty_len;
   if (type == Runtime::kUnknownMethod) {
-    Method* caller = *caller_sp;
+    DCHECK(called->IsRuntimeMethod());
     // less two as return address may span into next dex instruction
     uint32_t dex_pc = caller->ToDexPC(caller_pc - 2);
     const DexFile::CodeItem* code = MethodHelper(caller).GetCodeItem();
@@ -440,8 +434,26 @@
                 (instr_code == Instruction::INVOKE_STATIC_RANGE);
     DCHECK(is_static || (instr_code == Instruction::INVOKE_DIRECT) ||
            (instr_code == Instruction::INVOKE_DIRECT_RANGE));
+    Instruction::DecodedInstruction dec_insn(instr);
+    dex_method_idx = dec_insn.vB_;
+    shorty = linker->MethodShorty(dex_method_idx, caller, &shorty_len);
   } else {
+    DCHECK(!called->IsRuntimeMethod());
     is_static = type == Runtime::kStaticMethod;
+    dex_method_idx = called->GetDexMethodIndex();
+    MethodHelper mh(called);
+    shorty = mh.GetShorty();
+    shorty_len = mh.GetShortyLength();
+  }
+  // Discover shorty (avoid GCs)
+  size_t args_in_regs = 0;
+  for (size_t i = 1; i < shorty_len; i++) {
+    char c = shorty[i];
+    args_in_regs = args_in_regs + (c == 'J' || c == 'D' ? 2 : 1);
+    if (args_in_regs > 3) {
+      args_in_regs = 3;
+      break;
+    }
   }
   // Place into local references incoming arguments from the caller's register arguments
   size_t cur_arg = 1;   // skip method_idx in R0, first arg is in R1
@@ -478,20 +490,23 @@
     cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
   }
   // Resolve method filling in dex cache
-  Method* called = linker->ResolveMethod(method_idx, *caller_sp, true);
+  if (type == Runtime::kUnknownMethod) {
+    called = linker->ResolveMethod(dex_method_idx, caller, true);
+  }
+  const void* code = NULL;
   if (LIKELY(!thread->IsExceptionPending())) {
     if (LIKELY(called->IsDirect())) {
-      // Ensure that the called method's class is initialized
+      // Ensure that the called method's class is initialized.
       Class* called_class = called->GetDeclaringClass();
       linker->EnsureInitialized(called_class, true);
       if (LIKELY(called_class->IsInitialized())) {
-        // Update CodeAndDirectMethod table and avoid the trampoline when we know the called class
-        // is initialized (see test 084-class-init SlowInit)
-        Method* caller = *caller_sp;
-        DexCache* dex_cache = caller->GetDeclaringClass()->GetDexCache();
-        dex_cache->GetCodeAndDirectMethods()->SetResolvedDirectMethod(method_idx, called);
-        // We got this far, ensure that the declaring class is initialized
-        linker->EnsureInitialized(called->GetDeclaringClass(), true);
+        code = called->GetCode();
+      } else if (called_class->IsInitializing()) {
+        // Class is still initializing, go to oat and grab code (trampoline must be left in place
+        // until class is initialized to stop races between threads).
+        code = linker->GetOatCodeFor(called);
+      } else {
+        DCHECK(called_class->IsErroneous());
       }
     } else {
       // Direct method has been made virtual
@@ -500,19 +515,19 @@
                                  PrettyMethod(called, true).c_str());
     }
   }
-  void* code;
-  if (UNLIKELY(thread->IsExceptionPending())) {
+  if (UNLIKELY(code == NULL)) {
     // Something went wrong in ResolveMethod or EnsureInitialized,
     // go into deliver exception with the pending exception in r0
     code = reinterpret_cast<void*>(art_deliver_exception_from_code);
     regs[0] = reinterpret_cast<uintptr_t>(thread->GetException());
     thread->ClearException();
   } else {
-    // Expect class to at least be initializing
+    // Expect class to at least be initializing.
     DCHECK(called->GetDeclaringClass()->IsInitializing());
+    // Don't want infinite recursion.
+    DCHECK(code != Runtime::Current()->GetResolutionStubArray(Runtime::kUnknownMethod)->GetData());
     // Set up entry into main method
     regs[0] = reinterpret_cast<uintptr_t>(called);
-    code = const_cast<void*>(called->GetCode());
   }
   return code;
 }
@@ -581,7 +596,12 @@
     }
   }
   // Load expected destination, see Method::RegisterNative
-  return reinterpret_cast<const void*>(jni_method->GetGcMapRaw());
+  const void* code = reinterpret_cast<const void*>(jni_method->GetGcMapRaw());
+  if (UNLIKELY(code == NULL)) {
+    code = Runtime::Current()->GetJniDlsymLookupStub()->GetData();
+    jni_method->RegisterNative(self, code);
+  }
+  return code;
 }
 
 
@@ -1112,23 +1132,6 @@
   return ResolveVerifyAndClinit(type_idx, referrer, self, false, true);
 }
 
-// Helper function to resolve virtual method
-extern "C" Method* artResolveMethodFromCode(Method* referrer,
-                                            uint32_t method_idx,
-                                            bool is_direct,
-                                            Thread* self,
-                                            Method** sp) {
-    /*
-     * Slow-path handler on invoke virtual method path in which
-     * base method is unresolved at compile-time.  Caller will
-     * unwind if can't resolve.
-     */
-    FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-    Method* method = class_linker->ResolveMethod(method_idx, referrer, is_direct);
-    return method;
-}
-
 String* ResolveStringFromCode(const Method* referrer, uint32_t string_idx) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   return class_linker->ResolveString(string_idx, referrer);
@@ -1355,8 +1358,7 @@
       return 0;  // failure
     }
   }
-  // TODO: DCHECK
-  CHECK(!self->IsExceptionPending());
+  DCHECK(!self->IsExceptionPending());
   const void* code = method->GetCode();
 
   uint32_t method_uint = reinterpret_cast<uint32_t>(method);
@@ -1498,17 +1500,17 @@
   }
   // Convert proxy method into expected interface method
   Method* interface_method = proxy_method->FindOverriddenMethod();
-  CHECK(interface_method != NULL);
-  CHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
+  DCHECK(interface_method != NULL);
+  DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
   args_jobj[1].l = AddLocalReference<jobject>(env, interface_method);
   // Box arguments
   cur_arg = 0;  // reset stack location to read to start
   // reset index, will index into param type array which doesn't include the receiver
   param_index = 0;
   ObjectArray<Class>* param_types = proxy_mh.GetParameterTypes();
-  CHECK(param_types != NULL);
+  DCHECK(param_types != NULL);
   // Check number of parameter types agrees with number from the Method - less 1 for the receiver.
-  CHECK_EQ(static_cast<size_t>(param_types->GetLength()), num_params - 1);
+  DCHECK_EQ(static_cast<size_t>(param_types->GetLength()), num_params - 1);
   while (cur_arg < args_in_regs && param_index < (num_params - 1)) {
     Class* param_type = param_types->Get(param_index);
     Object* obj;
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 5831b16..3ee0012 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -34,7 +34,8 @@
                                 bool is_static, bool is_primitive, bool is_set, size_t expected_size);
 extern void* FindNativeMethod(Thread* thread);
 extern void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** sp);
-void* UnresolvedDirectMethodTrampolineFromCode(int32_t, Method**, Thread*, Runtime::TrampolineType);
+const void* UnresolvedDirectMethodTrampolineFromCode(Method*, Method**, Thread*,
+                                                     Runtime::TrampolineType);
 extern Class* ResolveVerifyAndClinit(uint32_t type_idx, const Method* referrer, Thread* self,
                                      bool can_run_clinit, bool verify_access);
 extern Class* InitializeTypeFromCode(uint32_t type_idx, Method* method);
@@ -97,7 +98,6 @@
   extern "C" void art_trace_entry_from_code(void*);
   extern "C" void art_trace_exit_from_code();
   extern "C" void* art_resolve_string_from_code(void*, uint32_t);
-  extern "C" void* art_resolve_method_from_code(void* referrer, uint32_t method_idx, bool is_direct);
   extern "C" void art_update_debugger(void*, void*, int32_t, void*);
   extern "C" void art_work_around_app_jni_bugs();
 
diff --git a/src/runtime_support_arm.S b/src/runtime_support_arm.S
index efa6ef8..18f2ae3 100644
--- a/src/runtime_support_arm.S
+++ b/src/runtime_support_arm.S
@@ -559,22 +559,6 @@
     bxeq   lr                            @ return on success
     DELIVER_PENDING_EXCEPTION
 
-   .global art_resolve_method_from_code
-    .extern artResolveMethodFromCode
-    /*
-     * Entry from managed code to resolve a method.
-     */
-art_resolve_method_from_code:
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case of GC
-    mov    r3, r9                     @ pass Thread::Current
-    str    sp, [sp, #0]               @ pass SP
-    @ artResolveMethodFromCode(Method* referrer, uint32_t method_idx, bool is_direct, Thread*, SP)
-    bl     artResolveMethodFromCode
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
-    cmp    r0, #0                     @ success if result is non-null
-    bxne   lr                         @ return on success
-    DELIVER_PENDING_EXCEPTION
-
     .global art_resolve_string_from_code
     .extern artResolveStringFromCode
     /*
diff --git a/src/space.cc b/src/space.cc
index 73701cd..32d3f3e 100644
--- a/src/space.cc
+++ b/src/space.cc
@@ -329,6 +329,9 @@
   runtime->SetResolutionStubArray(
       down_cast<ByteArray*>(resolution_stub_array), Runtime::kUnknownMethod);
 
+  Object* resolution_method = image_header.GetImageRoot(ImageHeader::kResolutionMethod);
+  runtime->SetResolutionMethod(down_cast<Method*>(resolution_method));
+
   Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod);
   runtime->SetCalleeSaveMethod(down_cast<Method*>(callee_save_method), Runtime::kSaveAll);
   callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsOnlySaveMethod);
diff --git a/src/thread.cc b/src/thread.cc
index fa9c44c..74107d5 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -138,7 +138,6 @@
   pThrowStackOverflowFromCode = art_throw_stack_overflow_from_code;
   pThrowVerificationErrorFromCode = art_throw_verification_error_from_code;
   pUnlockObjectFromCode = art_unlock_object_from_code;
-  pResolveMethodFromCode = art_resolve_method_from_code;
   pUpdateDebuggerFromCode = NULL;  // To enable, set to art_update_debugger
 #endif
   pF2l = F2L;
diff --git a/src/thread.h b/src/thread.h
index 4aa77dd..7963091 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -626,7 +626,6 @@
   void* (*pInitializeTypeFromCode)(uint32_t, void*);
   void* (*pInitializeTypeAndVerifyAccessFromCode)(uint32_t, void*);
   void (*pLockObjectFromCode)(void*);
-  void* (*pResolveMethodFromCode)(void*, uint32_t, bool);
   void* (*pResolveStringFromCode)(void*, uint32_t);
   int (*pSet32Instance)(uint32_t, void*, int32_t);  // field_idx, obj, src
   int (*pSet64Instance)(uint32_t, void*, int64_t);
@@ -643,8 +642,8 @@
   void (*pThrowNoSuchMethodFromCode)(int32_t);
   void (*pThrowAbstractMethodErrorFromCode)(Method* method, Thread* thread, Method** sp);
   void (*pUnlockObjectFromCode)(void*);
-  void* (*pUnresolvedDirectMethodTrampolineFromCode)(int32_t, Method**, Thread*,
-                                                     Runtime::TrampolineType);
+  const void* (*pUnresolvedDirectMethodTrampolineFromCode)(Method*, Method**, Thread*,
+                                                           Runtime::TrampolineType);
   void (*pUpdateDebuggerFromCode)(void*, void*, int32_t, void*);
 
  private:
diff --git a/src/trace.cc b/src/trace.cc
index 3c2f1b2..f5d118d 100644
--- a/src/trace.cc
+++ b/src/trace.cc
@@ -121,16 +121,6 @@
       tracer->SaveAndUpdateCode(method, trace_stub);
     }
   }
-
-  if (!klass->IsArrayClass() && !klass->IsPrimitive()) {
-    CodeAndDirectMethods* c_and_dm = klass->GetDexCache()->GetCodeAndDirectMethods();
-    for (size_t i = 0; i < c_and_dm->NumCodeAndDirectMethods(); i++) {
-      Method* method = c_and_dm->GetResolvedMethod(i);
-      if (method != NULL && (size_t) method != i) {
-        c_and_dm->SetResolvedDirectMethodTraceEntry(i, trace_stub);
-      }
-    }
-  }
   return true;
 }
 
@@ -149,20 +139,6 @@
       tracer->ResetSavedCode(method);
     }
   }
-
-  if (!klass->IsArrayClass() && !klass->IsPrimitive()) {
-    CodeAndDirectMethods* c_and_dm = klass->GetDexCache()->GetCodeAndDirectMethods();
-    for (size_t i = 0; i < c_and_dm->NumCodeAndDirectMethods(); i++) {
-      const void* code = c_and_dm->GetResolvedCode(i);
-      if (code == trace_stub) {
-        Method* method = klass->GetDexCache()->GetResolvedMethod(i);
-        if (tracer->GetSavedCodeFromMap(method) != NULL) {
-          tracer->ResetSavedCode(method);
-        }
-        c_and_dm->SetResolvedDirectMethod(i, method);
-      }
-    }
-  }
   return true;
 }