Removing remaining compiled stubs from image.

Abstract method error stub and jni dlsym lookup stubs are gone.
After this change, the image no longer needs to be executable.

Change-Id: Ic75d72bf7e76e3b8ecc596e82af68ab592dde15e
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 59426a4..c8212ef 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -222,9 +222,6 @@
 	src/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc \
 	src/native/sun_misc_Unsafe.cc \
 	src/oat.cc \
-	src/oat/runtime/arm/stub_arm.cc \
-	src/oat/runtime/mips/stub_mips.cc \
-	src/oat/runtime/x86/stub_x86.cc \
 	src/oat/utils/arm/assembler_arm.cc \
 	src/oat/utils/arm/managed_register_arm.cc \
 	src/oat/utils/assembler.cc \
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 9dee36a..d262a5d 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1600,7 +1600,7 @@
 
   Runtime* runtime = Runtime::Current();
   if (method->IsAbstract()) {
-    method->SetCode(runtime->GetAbstractMethodErrorStubArray()->GetData());
+    method->SetCode(GetAbstractMethodErrorStub());
     return;
   }
 
diff --git a/src/common_test.h b/src/common_test.h
index 05b0e05..6876274 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -234,8 +234,7 @@
     } else {
       const void* method_code;
       if (method->IsAbstract()) {
-        MakeExecutable(runtime_->GetAbstractMethodErrorStubArray());
-        method_code = runtime_->GetAbstractMethodErrorStubArray()->GetData();
+        method_code = GetAbstractMethodErrorStub();
       } else {
         // No code? You must mean to go into the interpreter.
         method_code = GetInterpreterEntryPoint();
@@ -353,8 +352,6 @@
     CompilerBackend compiler_backend = kQuick;
 #endif
 
-    runtime_->SetJniDlsymLookupStub(CompilerDriver::CreateJniDlsymLookupStub(instruction_set));
-    runtime_->SetAbstractMethodErrorStubArray(CompilerDriver::CreateAbstractMethodErrorStub(instruction_set));
     if (!runtime_->HasResolutionMethod()) {
       runtime_->SetResolutionMethod(runtime_->CreateResolutionMethod());
     }
@@ -487,8 +484,6 @@
     CHECK(method != NULL);
     compiler_driver_->CompileOne(method);
     MakeExecutable(method);
-
-    MakeExecutable(runtime_->GetJniDlsymLookupStub());
   }
 
   void CompileDirectMethod(mirror::ClassLoader* class_loader,
diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc
index e6f4b67..1660914 100644
--- a/src/compiler/driver/compiler_driver.cc
+++ b/src/compiler/driver/compiler_driver.cc
@@ -28,7 +28,6 @@
 #include "dex_file-inl.h"
 #include "jni_internal.h"
 #include "oat_file.h"
-#include "oat/runtime/stub.h"
 #include "object_utils.h"
 #include "runtime.h"
 #include "gc/card_table-inl.h"
@@ -409,36 +408,6 @@
   return res;
 }
 
-mirror::ByteArray* CompilerDriver::CreateJniDlsymLookupStub(InstructionSet instruction_set) {
-  switch (instruction_set) {
-    case kArm:
-    case kThumb2:
-      return arm::CreateJniDlsymLookupStub();
-    case kMips:
-      return mips::CreateJniDlsymLookupStub();
-    case kX86:
-      return x86::CreateJniDlsymLookupStub();
-    default:
-      LOG(FATAL) << "Unknown InstructionSet: " << instruction_set;
-      return NULL;
-  }
-}
-
-mirror::ByteArray* CompilerDriver::CreateAbstractMethodErrorStub(InstructionSet instruction_set) {
-  switch (instruction_set) {
-    case kArm:
-    case kThumb2:
-      return arm::CreateAbstractMethodErrorStub();
-    case kMips:
-      return mips::CreateAbstractMethodErrorStub();
-    case kX86:
-      return x86::CreateAbstractMethodErrorStub();
-    default:
-      LOG(FATAL) << "Unknown InstructionSet: " << instruction_set;
-      return NULL;
-  }
-}
-
 void CompilerDriver::CompileAll(jobject class_loader,
                                 const std::vector<const DexFile*>& dex_files) {
   DCHECK(!Runtime::Current()->IsStarted());
diff --git a/src/compiler/driver/compiler_driver.h b/src/compiler/driver/compiler_driver.h
index 3581f5f..a20e5ef 100644
--- a/src/compiler/driver/compiler_driver.h
+++ b/src/compiler/driver/compiler_driver.h
@@ -102,13 +102,6 @@
 
   CompilerTls* GetTls();
 
-  // Stub to throw AbstractMethodError
-  static mirror::ByteArray* CreateAbstractMethodErrorStub(InstructionSet instruction_set)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  static mirror::ByteArray* CreateJniDlsymLookupStub(InstructionSet instruction_set)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   // A class is uniquely located by its DexFile and the class_defs_ table index into that DexFile
   typedef std::pair<const DexFile*, uint32_t> ClassReference;
 
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 36b8d26..e41e537 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -372,12 +372,6 @@
     }
     Runtime* runtime = Runtime::Current();
     // if we loaded an existing image, we will reuse values from the image roots.
-    if (!runtime->HasJniDlsymLookupStub()) {
-      runtime->SetJniDlsymLookupStub(CompilerDriver::CreateJniDlsymLookupStub(instruction_set));
-    }
-    if (!runtime->HasAbstractMethodErrorStubArray()) {
-      runtime->SetAbstractMethodErrorStubArray(CompilerDriver::CreateAbstractMethodErrorStub(instruction_set));
-    }
     if (!runtime->HasResolutionMethod()) {
       runtime->SetResolutionMethod(runtime->CreateResolutionMethod());
     }
diff --git a/src/gc/space.cc b/src/gc/space.cc
index d7378c3..bfc3e86 100644
--- a/src/gc/space.cc
+++ b/src/gc/space.cc
@@ -512,12 +512,6 @@
   DCHECK_EQ(0, memcmp(&image_header, map->Begin(), sizeof(ImageHeader)));
 
   Runtime* runtime = Runtime::Current();
-  mirror::Object* jni_stub_array = image_header.GetImageRoot(ImageHeader::kJniStubArray);
-  runtime->SetJniDlsymLookupStub(down_cast<mirror::ByteArray*>(jni_stub_array));
-
-  mirror::Object* ame_stub_array = image_header.GetImageRoot(ImageHeader::kAbstractMethodErrorStubArray);
-  runtime->SetAbstractMethodErrorStubArray(down_cast<mirror::ByteArray*>(ame_stub_array));
-
   mirror::Object* resolution_method = image_header.GetImageRoot(ImageHeader::kResolutionMethod);
   runtime->SetResolutionMethod(down_cast<mirror::AbstractMethod*>(resolution_method));
 
diff --git a/src/image.cc b/src/image.cc
index c746c8e..686a117 100644
--- a/src/image.cc
+++ b/src/image.cc
@@ -24,7 +24,7 @@
 namespace art {
 
 const byte ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const byte ImageHeader::kImageVersion[] = { '0', '0', '3', '\0' };
+const byte ImageHeader::kImageVersion[] = { '0', '0', '4', '\0' };
 
 ImageHeader::ImageHeader(uint32_t image_begin,
                          uint32_t image_roots,
diff --git a/src/image.h b/src/image.h
index 040e3fe..f14d7d1 100644
--- a/src/image.h
+++ b/src/image.h
@@ -81,8 +81,6 @@
   }
 
   enum ImageRoot {
-    kJniStubArray,
-    kAbstractMethodErrorStubArray,
     kResolutionMethod,
     kCalleeSaveMethod,
     kRefsOnlySaveMethod,
diff --git a/src/image_test.cc b/src/image_test.cc
index e4deda3..192e28a 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -127,8 +127,6 @@
   ASSERT_TRUE(runtime_.get() != NULL);
   class_linker_ = runtime_->GetClassLinker();
 
-  ASSERT_TRUE(runtime_->GetJniDlsymLookupStub() != NULL);
-
   Heap* heap = Runtime::Current()->GetHeap();
   ASSERT_EQ(2U, heap->GetSpaces().size());
   ASSERT_TRUE(heap->GetSpaces()[0]->IsImageSpace());
diff --git a/src/image_writer.cc b/src/image_writer.cc
index 16ac385..d9e4353 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -351,9 +351,6 @@
       image_roots(self,
                   ObjectArray<Object>::Alloc(self, object_array_class,
                                              ImageHeader::kImageRootsMax));
-  image_roots->Set(ImageHeader::kJniStubArray, runtime->GetJniDlsymLookupStub());
-  image_roots->Set(ImageHeader::kAbstractMethodErrorStubArray,
-                   runtime->GetAbstractMethodErrorStubArray());
   image_roots->Set(ImageHeader::kResolutionMethod, runtime->GetResolutionMethod());
   image_roots->Set(ImageHeader::kCalleeSaveMethod,
                    runtime->GetCalleeSaveMethod(Runtime::kSaveAll));
@@ -478,10 +475,8 @@
   // OatWriter replaces the code_ with an offset value.
   // Here we readjust to a pointer relative to oat_begin_
   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->SetCode(copy_ame_stub_array_->GetData());
+    // Code for abstract methods is set to the abstract method error stub when we load the image.
+    copy->SetCode(NULL);
     return;
   }
 
@@ -495,11 +490,9 @@
   copy->SetCode(GetOatAddress(orig->GetOatCodeOffset()));
 
   if (orig->IsNative()) {
-    // The native method's pointer is directed to a stub to lookup via dlsym.
+    // The native method's pointer is set to a stub to lookup via dlsym when we load the image.
     // Note this is not the code_ pointer, that is handled above.
-    ByteArray* orig_jni_stub_array_ = Runtime::Current()->GetJniDlsymLookupStub();
-    ByteArray* copy_jni_stub_array_ = down_cast<ByteArray*>(GetImageAddress(orig_jni_stub_array_));
-    copy->SetNativeMethod(copy_jni_stub_array_->GetData());
+    copy->SetNativeMethod(NULL);
   } else {
     // normal (non-abstract non-native) methods have mapping tables to relocate
     uint32_t mapping_table_off = orig->GetOatMappingTableOffset();
diff --git a/src/jni_internal.h b/src/jni_internal.h
index 131032a..dc6ca4a 100644
--- a/src/jni_internal.h
+++ b/src/jni_internal.h
@@ -51,7 +51,6 @@
 void SetJniGlobalsMax(size_t max);
 void JniAbortF(const char* jni_function_name, const char* fmt, ...)
     __attribute__((__format__(__printf__, 2, 3)));
-void* FindNativeMethod(Thread* thread);
 void RegisterNativeMethods(JNIEnv* env, const char* jni_class_name, const JNINativeMethod* methods,
                            size_t method_count);
 
diff --git a/src/mirror/abstract_method.cc b/src/mirror/abstract_method.cc
index 3ab3a93..559b558 100644
--- a/src/mirror/abstract_method.cc
+++ b/src/mirror/abstract_method.cc
@@ -324,7 +324,7 @@
 bool AbstractMethod::IsRegistered() const {
   void* native_method = GetFieldPtr<void*>(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, native_method_), false);
   CHECK(native_method != NULL);
-  void* jni_stub = Runtime::Current()->GetJniDlsymLookupStub()->GetData();
+  void* jni_stub = GetJniDlsymLookupStub();
   return native_method != jni_stub;
 }
 
@@ -352,7 +352,7 @@
 void AbstractMethod::UnregisterNative(Thread* self) {
   CHECK(IsNative()) << PrettyMethod(this);
   // restore stub to lookup native pointer via dlsym
-  RegisterNative(self, Runtime::Current()->GetJniDlsymLookupStub()->GetData());
+  RegisterNative(self, GetJniDlsymLookupStub());
 }
 
 void AbstractMethod::SetNativeMethod(const void* native_method) {
diff --git a/src/oat/runtime/arm/oat_support_entrypoints_arm.cc b/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
index dcf6bb8..1a5fe47 100644
--- a/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
+++ b/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
@@ -109,8 +109,6 @@
 extern "C" void art_quick_test_suspend();
 
 // Throw entrypoints.
-extern void ThrowAbstractMethodErrorFromCode(mirror::AbstractMethod* method, Thread* thread,
-                                             mirror::AbstractMethod** sp);
 extern "C" void art_quick_deliver_exception_from_code(void*);
 extern "C" void art_quick_throw_array_bounds_from_code(int32_t index, int32_t limit);
 extern "C" void art_quick_throw_div_zero_from_code();
@@ -156,7 +154,6 @@
   points->pHandleFillArrayDataFromCode = art_quick_handle_fill_data_from_code;
 
   // JNI
-  points->pFindNativeMethod = FindNativeMethod;
   points->pJniMethodStart = JniMethodStart;
   points->pJniMethodStartSynchronized = JniMethodStartSynchronized;
   points->pJniMethodEnd = JniMethodEnd;
@@ -210,7 +207,6 @@
 
   // Throws
   points->pDeliverException = art_quick_deliver_exception_from_code;
-  points->pThrowAbstractMethodErrorFromCode = ThrowAbstractMethodErrorFromCode;
   points->pThrowArrayBoundsFromCode = art_quick_throw_array_bounds_from_code;
   points->pThrowDivZeroFromCode = art_quick_throw_div_zero_from_code;
   points->pThrowNoSuchMethodFromCode = art_quick_throw_no_such_method_from_code;
diff --git a/src/oat/runtime/arm/runtime_support_arm.S b/src/oat/runtime/arm/runtime_support_arm.S
index 2aa380b..3578ba0 100644
--- a/src/oat/runtime/arm/runtime_support_arm.S
+++ b/src/oat/runtime/arm/runtime_support_arm.S
@@ -257,6 +257,7 @@
     .cfi_adjust_cfa_offset 20
     sub    sp, #12                        @ pad stack pointer to align frame
     .pad #12
+    .cfi_adjust_cfa_offset 12
     mov    r2, r9                         @ pass Thread::Current
     mov    r1, sp                         @ pass stack pointer
     blx    artPortableResolutionTrampoline   @ (method_idx, sp, Thread*)
@@ -1067,6 +1068,49 @@
 END art_quick_deoptimize
 
     /*
+     * Portable abstract method error stub. r0 contains method* on entry. SP unused in portable.
+     */
+    .extern artThrowAbstractMethodErrorFromCode
+ENTRY art_portable_abstract_method_error_stub
+    mov    r1, r9         @ pass Thread::Current
+    b      artThrowAbstractMethodErrorFromCode  @ (Method*, Thread*, SP)
+END art_portable_abstract_method_error_stub
+
+    /*
+     * Quick abstract method error stub. r0 contains method* on entry.
+     */
+ENTRY art_quick_abstract_method_error_stub
+    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
+    mov    r1, r9         @ pass Thread::Current
+    mov    r2, sp         @ pass SP
+    b      artThrowAbstractMethodErrorFromCode  @ (Method*, Thread*, SP)
+END art_quick_abstract_method_error_stub
+
+    /*
+     * Jni dlsym lookup stub.
+     */
+    .extern artFindNativeMethod
+ENTRY art_jni_dlsym_lookup_stub
+    push   {r0, r1, r2, r3, lr}           @ spill regs
+    .save  {r0, r1, r2, r3, lr}
+    .pad #20
+    .cfi_adjust_cfa_offset 20
+    sub    sp, #12                        @ pad stack pointer to align frame
+    .pad #12
+    .cfi_adjust_cfa_offset 12
+    mov    r0, r9                         @ pass Thread::Current
+    blx    artFindNativeMethod            @ (Thread*)
+    mov    r12, r0                        @ save result in r12
+    add    sp, #12                        @ restore stack pointer
+    .cfi_adjust_cfa_offset -12
+    pop    {r0, r1, r2, r3, lr}           @ restore regs
+    .cfi_adjust_cfa_offset -20
+    cmp    r12, #0                        @ is method code null?
+    bxne   r12                            @ if non-null, tail call to method's code
+    bx     lr                             @ otherwise, return to caller to handle exception
+END art_jni_dlsym_lookup_stub
+
+    /*
      * Signed 64-bit integer multiply.
      *
      * Consider WXxYZ (r1r0 x r3r2) with a long multiply:
diff --git a/src/oat/runtime/arm/stub_arm.cc b/src/oat/runtime/arm/stub_arm.cc
deleted file mode 100644
index 7c97f4c..0000000
--- a/src/oat/runtime/arm/stub_arm.cc
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "jni_internal.h"
-#include "mirror/array.h"
-#include "mirror/object-inl.h"
-#include "oat/utils/arm/assembler_arm.h"
-#include "oat/runtime/oat_support_entrypoints.h"
-#include "oat/runtime/stub.h"
-#include "stack_indirect_reference_table.h"
-#include "sirt_ref.h"
-
-#define __ assembler->
-
-namespace art {
-namespace arm {
-
-typedef void (*ThrowAme)(mirror::AbstractMethod*, Thread*);
-
-mirror::ByteArray* CreateAbstractMethodErrorStub() {
-  UniquePtr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm)));
-#if !defined(ART_USE_PORTABLE_COMPILER)
-  // Save callee saves and ready frame for exception delivery
-  RegList save = (1 << R4) | (1 << R5) | (1 << R6) | (1 << R7) | (1 << R8) | (1 << R9) |
-                 (1 << R10) | (1 << R11) | (1 << LR);
-  // TODO: enable when GetCalleeSaveMethod is available at stub generation time
-  // DCHECK_EQ(save, Runtime::Current()->GetCalleeSaveMethod(Runtime::kSaveAll)->GetCoreSpillMask());
-  __ PushList(save);         // push {r4-r11, lr} - 9 words of callee saves
-  // TODO: enable when GetCalleeSaveMethod is available at stub generation time
-  // DCHECK_EQ(Runtime::Current()->GetCalleeSaveMethod(Runtime::kSaveAll)->GetFpSpillMask(), 0xFFFFU);
-  __ Emit(0xed2d0a20);       // vpush {s0-s31}
-
-  __ IncreaseFrameSize(12);  // 3 words of space, bottom word will hold callee save Method*
-
-  // R0 is the Method* already
-  __ mov(R1, ShifterOperand(R9));  // Pass Thread::Current() in R1
-  __ mov(R2, ShifterOperand(SP));  // Pass SP in R2
-  // Call to throw AbstractMethodError
-  __ LoadFromOffset(kLoadWord, R12, TR, ENTRYPOINT_OFFSET(pThrowAbstractMethodErrorFromCode));
-  __ mov(PC, ShifterOperand(R12));  // Leaf call to routine that never returns
-
-  __ bkpt(0);
-#else // ART_USE_PORTABLE_COMPILER
-  // R0 is the Method* already
-  __ mov(R1, ShifterOperand(R9));  // Pass Thread::Current() in R1
-  // Call to throw AbstractMethodError
-  __ LoadFromOffset(kLoadWord, R12, TR, ENTRYPOINT_OFFSET(pThrowAbstractMethodErrorFromCode));
-  __ mov(PC, ShifterOperand(R12));  // Leaf call to routine that never returns
-
-  __ bkpt(0);
-#endif // ART_USE_PORTABLE_COMPILER
-
-  assembler->EmitSlowPaths();
-
-  size_t cs = assembler->CodeSize();
-  Thread* self = Thread::Current();
-  SirtRef<mirror::ByteArray> abstract_stub(self, mirror::ByteArray::Alloc(self, cs));
-  CHECK(abstract_stub.get() != NULL);
-  MemoryRegion code(abstract_stub->GetData(), abstract_stub->GetLength());
-  assembler->FinalizeInstructions(code);
-
-  return abstract_stub.get();
-}
-
-mirror::ByteArray* CreateJniDlsymLookupStub() {
-  UniquePtr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm)));
-  // Build frame and save argument registers and LR.
-  RegList save = (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3) | (1 << LR);
-  __ PushList(save);
-  __ AddConstant(SP, -12);         // Ensure 16-byte alignment
-  __ mov(R0, ShifterOperand(R9));  // Pass Thread::Current() in R0
-  // Call FindNativeMethod
-  __ LoadFromOffset(kLoadWord, R12, TR, ENTRYPOINT_OFFSET(pFindNativeMethod));
-  __ blx(R12);
-  __ mov(R12, ShifterOperand(R0));  // Save result of FindNativeMethod in R12
-  __ AddConstant(SP, 12);           // Restore registers (including outgoing arguments)
-  __ PopList(save);
-  __ cmp(R12, ShifterOperand(0));
-  __ bx(R12, NE);                   // If R12 != 0 tail call into native code
-  __ bx(LR);                        // Return to caller to handle exception
-
-  assembler->EmitSlowPaths();
-
-  size_t cs = assembler->CodeSize();
-  Thread* self = Thread::Current();
-  SirtRef<mirror::ByteArray> jni_stub(self, mirror::ByteArray::Alloc(self, cs));
-  CHECK(jni_stub.get() != NULL);
-  MemoryRegion code(jni_stub->GetData(), jni_stub->GetLength());
-  assembler->FinalizeInstructions(code);
-
-  return jni_stub.get();
-}
-
-} // namespace arm
-} // namespace art
diff --git a/src/oat/runtime/mips/oat_support_entrypoints_mips.cc b/src/oat/runtime/mips/oat_support_entrypoints_mips.cc
index b201b07..eb82c42 100644
--- a/src/oat/runtime/mips/oat_support_entrypoints_mips.cc
+++ b/src/oat/runtime/mips/oat_support_entrypoints_mips.cc
@@ -111,8 +111,6 @@
 extern "C" void art_quick_test_suspend();
 
 // Throw entrypoints.
-extern void ThrowAbstractMethodErrorFromCode(mirror::AbstractMethod* method, Thread* thread,
-                                             mirror::AbstractMethod** sp);
 extern "C" void art_quick_deliver_exception_from_code(void*);
 extern "C" void art_quick_throw_array_bounds_from_code(int32_t index, int32_t limit);
 extern "C" void art_quick_throw_div_zero_from_code();
@@ -158,7 +156,6 @@
   points->pHandleFillArrayDataFromCode = art_quick_handle_fill_data_from_code;
 
   // JNI
-  points->pFindNativeMethod = FindNativeMethod;
   points->pJniMethodStart = JniMethodStart;
   points->pJniMethodStartSynchronized = JniMethodStartSynchronized;
   points->pJniMethodEnd = JniMethodEnd;
@@ -211,7 +208,6 @@
 
   // Throws
   points->pDeliverException = art_quick_deliver_exception_from_code;
-  points->pThrowAbstractMethodErrorFromCode = ThrowAbstractMethodErrorFromCode;
   points->pThrowArrayBoundsFromCode = art_quick_throw_array_bounds_from_code;
   points->pThrowDivZeroFromCode = art_quick_throw_div_zero_from_code;
   points->pThrowNoSuchMethodFromCode = art_quick_throw_no_such_method_from_code;
diff --git a/src/oat/runtime/mips/runtime_support_mips.S b/src/oat/runtime/mips/runtime_support_mips.S
index f5f8d9b..295e3fe 100644
--- a/src/oat/runtime/mips/runtime_support_mips.S
+++ b/src/oat/runtime/mips/runtime_support_mips.S
@@ -408,10 +408,10 @@
 INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
 INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
 
-     /*
+    /*
      * Portable resolution trampoline.
      */
-     .extern artPortableResolutionTrampoline
+    .extern artPortableResolutionTrampoline
 ENTRY art_portable_resolution_trampoline
     GENERATE_GLOBAL_POINTER
     addiu $sp, $sp, -32          # leave room for $a0, $a1, $a2, $a3, and $ra
@@ -444,10 +444,10 @@
     nop
 END art_portable_resolution_trampoline
 
-     /*
+    /*
      * Quick resolution trampoline.
      */
-     .extern artQuickResolutionTrampoline
+    .extern artQuickResolutionTrampoline
 ENTRY art_quick_resolution_trampoline
     GENERATE_GLOBAL_POINTER
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
@@ -482,8 +482,8 @@
      *   [sp + 16] = JValue* result
      *   [sp + 20] = result type char
      */
-     .type art_portable_invoke_stub, %function
-     .global art_portable_invoke_stub
+    .type art_portable_invoke_stub, %function
+    .global art_portable_invoke_stub
 art_portable_invoke_stub:
 ENTRY art_quick_invoke_stub
     GENERATE_GLOBAL_POINTER
@@ -1102,6 +1102,64 @@
 END art_quick_deoptimize
 
     /*
+     * Portable abstract method error stub. $a0 contains method* on entry. SP unused in portable.
+     */
+    .extern artThrowAbstractMethodErrorFromCode
+ENTRY art_portable_abstract_method_error_stub
+    GENERATE_GLOBAL_POINTER
+    la       $t9, artThrowAbstractMethodErrorFromCode
+    jr       $t9            # (Method*, Thread*, SP)
+    move     $a1, $s1       # pass Thread::Current
+END art_portable_abstract_method_error_stub
+
+    /*
+     * Quick abstract method error stub. $a0 contains method* on entry.
+     */
+ENTRY art_quick_abstract_method_error_stub
+    GENERATE_GLOBAL_POINTER
+    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
+    move     $a1, $s1       # pass Thread::Current
+    la       $t9, artThrowAbstractMethodErrorFromCode
+    jr       $t9            # (Method*, Thread*, SP)
+    move     $a2, $sp       # pass SP
+END art_quick_abstract_method_error_stub
+
+    /*
+     * Jni dlsym lookup stub.
+     */
+    .extern artFindNativeMethod
+ENTRY art_jni_dlsym_lookup_stub
+    GENERATE_GLOBAL_POINTER
+    addiu $sp, $sp, -32          # leave room for $a0, $a1, $a2, $a3, and $ra
+    .cfi_adjust_cfa_offset 32
+    sw     $ra, 16($sp)
+    .cfi_rel_offset 31, 16
+    sw     $a3, 12($sp)
+    .cfi_rel_offset 7, 12
+    sw     $a2, 8($sp)
+    .cfi_rel_offset 6, 8
+    sw     $a1, 4($sp)
+    .cfi_rel_offset 5, 4
+    sw     $a0, 0($sp)
+    .cfi_rel_offset 4, 0
+    jal   artFindNativeMethod   # (Thread*)
+    move  $a0, $s1              # pass Thread::Current()
+    lw    $a0, 0($sp)           # restore registers from stack
+    lw    $a1, 4($sp)
+    lw    $a2, 8($sp)
+    lw    $a3, 12($sp)
+    lw    $ra, 16($sp)
+    beq   $v0, $zero, no_native_code_found
+    addiu $sp, $sp, 32          # restore the stack
+    .cfi_adjust_cfa_offset -32
+    jr    $t9                   # leaf call to method's code
+    move  $t9, $v0              # put method code result in $t9
+no_native_code_found:
+    jr    $ra
+    nop
+END art_jni_dlsym_lookup_stub
+
+    /*
      * Long integer shift.  This is different from the generic 32/64-bit
      * binary operations because vAA/vBB are 64-bit but vCC (the shift
      * distance) is 32-bit.  Also, Dalvik requires us to ignore all but the low
diff --git a/src/oat/runtime/mips/stub_mips.cc b/src/oat/runtime/mips/stub_mips.cc
deleted file mode 100644
index a1adf66..0000000
--- a/src/oat/runtime/mips/stub_mips.cc
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "jni_internal.h"
-#include "mirror/array.h"
-#include "mirror/object-inl.h"
-#include "oat/runtime/oat_support_entrypoints.h"
-#include "oat/runtime/stub.h"
-#include "oat/utils/mips/assembler_mips.h"
-#include "stack_indirect_reference_table.h"
-#include "sirt_ref.h"
-
-#define __ assembler->
-
-namespace art {
-namespace mips {
-
-typedef void (*ThrowAme)(mirror::AbstractMethod*, Thread*);
-
-mirror::ByteArray* CreateAbstractMethodErrorStub() {
-  UniquePtr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
-#if !defined(ART_USE_PORTABLE_COMPILER)
-  // Save callee saves and ready frame for exception delivery
-  __ AddConstant(SP, SP, -64);
-  __ StoreToOffset(kStoreWord, RA, SP, 60);
-  __ StoreToOffset(kStoreWord, FP, SP, 56);
-  __ StoreToOffset(kStoreWord, S7, SP, 52);
-  __ StoreToOffset(kStoreWord, S6, SP, 48);
-  __ StoreToOffset(kStoreWord, S5, SP, 44);
-  __ StoreToOffset(kStoreWord, S4, SP, 40);
-  __ StoreToOffset(kStoreWord, S3, SP, 36);
-  __ StoreToOffset(kStoreWord, S2, SP, 32);
-  __ StoreToOffset(kStoreWord, S1, SP, 28);
-  __ StoreToOffset(kStoreWord, S0, SP, 24);
-
-  // A0 is the Method* already
-  __ Move(A1, S1);  // Pass Thread::Current() in A1
-  __ Move(A2, SP);  // Pass SP in A2
-  // Call to throw AbstractMethodError
-  __ LoadFromOffset(kLoadWord, T9, S1, ENTRYPOINT_OFFSET(pThrowAbstractMethodErrorFromCode));
-  __ Jr(T9);  // Leaf call to routine that never returns
-
-  __ Break();
-#else // ART_USE_PORTABLE_COMPILER
-  // R0 is the Method* already
-  __ Move(A1, S1);  // Pass Thread::Current() in A1
-  // Call to throw AbstractMethodError
-  __ LoadFromOffset(kLoadWord, T9, S1, ENTRYPOINT_OFFSET(pThrowAbstractMethodErrorFromCode));
-  __ Jr(T9);  // Leaf call to routine that never returns
-
-  __ Break();
-#endif // ART_USE_PORTABLE_COMPILER
-
-  assembler->EmitSlowPaths();
-
-  size_t cs = assembler->CodeSize();
-  Thread* self = Thread::Current();
-  SirtRef<mirror::ByteArray> abstract_stub(self, mirror::ByteArray::Alloc(self, cs));
-  CHECK(abstract_stub.get() != NULL);
-  MemoryRegion code(abstract_stub->GetData(), abstract_stub->GetLength());
-  assembler->FinalizeInstructions(code);
-
-  return abstract_stub.get();
-}
-
-mirror::ByteArray* CreateJniDlsymLookupStub() {
-  UniquePtr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
-
-  // Build frame and save argument registers and RA.
-  __ AddConstant(SP, SP, -32);
-  __ StoreToOffset(kStoreWord, RA, SP, 28);
-  __ StoreToOffset(kStoreWord, A3, SP, 24);
-  __ StoreToOffset(kStoreWord, A2, SP, 20);
-  __ StoreToOffset(kStoreWord, A1, SP, 16);
-  __ StoreToOffset(kStoreWord, A0, SP, 12);
-
-  __ Move(A0, S1); // Pass Thread::Current() in A0
-  __ LoadFromOffset(kLoadWord, T9, S1, ENTRYPOINT_OFFSET(pFindNativeMethod));
-  __ Jalr(T9); // Call FindNativeMethod
-
-  // Restore frame, argument registers, and RA.
-  __ LoadFromOffset(kLoadWord, A0, SP, 12);
-  __ LoadFromOffset(kLoadWord, A1, SP, 16);
-  __ LoadFromOffset(kLoadWord, A2, SP, 20);
-  __ LoadFromOffset(kLoadWord, A3, SP, 24);
-  __ LoadFromOffset(kLoadWord, RA, SP, 28);
-  __ AddConstant(SP, SP, 32);
-
-  Label no_native_code_found;
-  __ EmitBranch(V0, ZERO, &no_native_code_found, true);
-  __ Move(T9, V0); // Move result into T9
-  __ Jr(T9); // If result != 0, tail call method's code
-  __ Bind(&no_native_code_found, false);
-  __ Jr(RA); // Return to caller to handle exception
-
-  assembler->EmitSlowPaths();
-
-  size_t cs = assembler->CodeSize();
-  Thread* self = Thread::Current();
-  SirtRef<mirror::ByteArray> jni_stub(self, mirror::ByteArray::Alloc(self, cs));
-  CHECK(jni_stub.get() != NULL);
-  MemoryRegion code(jni_stub->GetData(), jni_stub->GetLength());
-  assembler->FinalizeInstructions(code);
-
-  return jni_stub.get();
-}
-
-} // namespace mips
-} // namespace art
diff --git a/src/oat/runtime/oat_support_entrypoints.h b/src/oat/runtime/oat_support_entrypoints.h
index 5be1e49..72d5348 100644
--- a/src/oat/runtime/oat_support_entrypoints.h
+++ b/src/oat/runtime/oat_support_entrypoints.h
@@ -70,7 +70,6 @@
   void (*pHandleFillArrayDataFromCode)(void*, void*);
 
   // JNI
-  void* (*pFindNativeMethod)(Thread* thread);
   uint32_t (*pJniMethodStart)(Thread*);
   uint32_t (*pJniMethodStartSynchronized)(jobject to_lock, Thread* self);
   void (*pJniMethodEnd)(uint32_t cookie, Thread* self);
@@ -125,8 +124,6 @@
 
   // Throws
   void (*pDeliverException)(void*);
-  void (*pThrowAbstractMethodErrorFromCode)(mirror::AbstractMethod* m, Thread* thread,
-                                            mirror::AbstractMethod** sp);
   void (*pThrowArrayBoundsFromCode)(int32_t, int32_t);
   void (*pThrowDivZeroFromCode)();
   void (*pThrowNoSuchMethodFromCode)(int32_t);
@@ -135,7 +132,6 @@
 };
 
 // JNI entrypoints.
-extern void* FindNativeMethod(Thread* thread) LOCKS_EXCLUDED(Locks::mutator_lock_);
 extern uint32_t JniMethodStart(Thread* self)
     UNLOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot));
 extern uint32_t JniMethodStartSynchronized(jobject to_lock, Thread* self)
diff --git a/src/oat/runtime/stub.h b/src/oat/runtime/stub.h
deleted file mode 100644
index ee39273..0000000
--- a/src/oat/runtime/stub.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_SRC_OAT_RUNTIME_OAT_RUNTIME_STUB_H_
-#define ART_SRC_OAT_RUNTIME_OAT_RUNTIME_STUB_H_
-
-#include "runtime.h"
-
-namespace art {
-namespace mirror {
-template<class T> class PrimitiveArray;
-typedef PrimitiveArray<int8_t> ByteArray;
-}  // namespace mirror
-
-namespace arm {
-  mirror::ByteArray* CreateAbstractMethodErrorStub()
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  mirror::ByteArray* CreateJniDlsymLookupStub()
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-}
-
-namespace mips {
-  mirror::ByteArray* CreateAbstractMethodErrorStub()
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  mirror::ByteArray* CreateJniDlsymLookupStub()
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-}
-
-namespace x86 {
-  mirror::ByteArray* CreateAbstractMethodErrorStub()
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  mirror::ByteArray* CreateJniDlsymLookupStub()
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-}
-
-}  // namespace art
-
-#endif  // ART_SRC_OAT_RUNTIME_OAT_RUNTIME_STUB_H_
diff --git a/src/oat/runtime/support_jni.cc b/src/oat/runtime/support_jni.cc
index bc9cc45..8f0f7ca 100644
--- a/src/oat/runtime/support_jni.cc
+++ b/src/oat/runtime/support_jni.cc
@@ -27,28 +27,6 @@
 
 namespace art {
 
-// Used by the JNI dlsym stub to find the native method to invoke if none is registered.
-extern void* FindNativeMethod(Thread* self) {
-  Locks::mutator_lock_->AssertNotHeld(self);  // We come here as Native.
-  DCHECK(Thread::Current() == self);
-  ScopedObjectAccess soa(self);
-
-  mirror::AbstractMethod* method = self->GetCurrentMethod(NULL);
-  DCHECK(method != NULL);
-
-  // Lookup symbol address for method, on failure we'll return NULL with an
-  // exception set, otherwise we return the address of the method we found.
-  void* native_code = soa.Vm()->FindCodeForNativeMethod(method);
-  if (native_code == NULL) {
-    DCHECK(self->IsExceptionPending());
-    return NULL;
-  } else {
-    // Register so that future calls don't come here
-    method->RegisterNative(self, native_code);
-    return native_code;
-  }
-}
-
 // Called on entry to JNI, transition out of Runnable and release share of mutator_lock_.
 extern uint32_t JniMethodStart(Thread* self) {
   JNIEnvExt* env = self->GetJniEnv();
@@ -184,7 +162,7 @@
   // Load expected destination, see Method::RegisterNative
   const void* code = reinterpret_cast<const void*>(jni_method->GetNativeGcMap());
   if (UNLIKELY(code == NULL)) {
-    code = Runtime::Current()->GetJniDlsymLookupStub()->GetData();
+    code = GetJniDlsymLookupStub();
     jni_method->RegisterNative(self, code);
   }
   return code;
diff --git a/src/oat/runtime/support_stubs.cc b/src/oat/runtime/support_stubs.cc
index f78cc79..9f77ae0 100644
--- a/src/oat/runtime/support_stubs.cc
+++ b/src/oat/runtime/support_stubs.cc
@@ -335,9 +335,9 @@
   return code;
 }
 
-// Called by the AbstractMethodError. Called by stub code.
-extern void ThrowAbstractMethodErrorFromCode(mirror::AbstractMethod* method, Thread* self,
-                                             mirror::AbstractMethod** sp)
+// Called by the abstract method error stub.
+extern "C" void artThrowAbstractMethodErrorFromCode(mirror::AbstractMethod* method, Thread* self,
+                                                    mirror::AbstractMethod** sp)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
 #if !defined(ART_USE_PORTABLE_COMPILER)
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
@@ -350,4 +350,26 @@
   self->QuickDeliverException();
 }
 
+// Used by the JNI dlsym stub to find the native method to invoke if none is registered.
+extern "C" void* artFindNativeMethod(Thread* self) {
+  Locks::mutator_lock_->AssertNotHeld(self);  // We come here as Native.
+  DCHECK(Thread::Current() == self);
+  ScopedObjectAccess soa(self);
+
+  mirror::AbstractMethod* method = self->GetCurrentMethod(NULL);
+  DCHECK(method != NULL);
+
+  // Lookup symbol address for method, on failure we'll return NULL with an
+  // exception set, otherwise we return the address of the method we found.
+  void* native_code = soa.Vm()->FindCodeForNativeMethod(method);
+  if (native_code == NULL) {
+    DCHECK(self->IsExceptionPending());
+    return NULL;
+  } else {
+    // Register so that future calls don't come here
+    method->RegisterNative(self, native_code);
+    return native_code;
+  }
+}
+
 }  // namespace art
diff --git a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
index 2e35d78..357bbe0 100644
--- a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
+++ b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
@@ -94,8 +94,6 @@
 extern "C" void art_quick_test_suspend();
 
 // Throw entrypoints.
-extern void ThrowAbstractMethodErrorFromCode(mirror::AbstractMethod* method, Thread* thread,
-                                             mirror::AbstractMethod** sp);
 extern "C" void art_quick_deliver_exception_from_code(void*);
 extern "C" void art_quick_throw_array_bounds_from_code(int32_t index, int32_t limit);
 extern "C" void art_quick_throw_div_zero_from_code();
@@ -141,7 +139,6 @@
   points->pHandleFillArrayDataFromCode = art_quick_handle_fill_data_from_code;
 
   // JNI
-  points->pFindNativeMethod = FindNativeMethod;
   points->pJniMethodStart = JniMethodStart;
   points->pJniMethodStartSynchronized = JniMethodStartSynchronized;
   points->pJniMethodEnd = JniMethodEnd;
@@ -194,7 +191,6 @@
 
   // Throws
   points->pDeliverException = art_quick_deliver_exception_from_code;
-  points->pThrowAbstractMethodErrorFromCode = ThrowAbstractMethodErrorFromCode;
   points->pThrowArrayBoundsFromCode = art_quick_throw_array_bounds_from_code;
   points->pThrowDivZeroFromCode = art_quick_throw_div_zero_from_code;
   points->pThrowNoSuchMethodFromCode = art_quick_throw_no_such_method_from_code;
diff --git a/src/oat/runtime/x86/runtime_support_x86.S b/src/oat/runtime/x86/runtime_support_x86.S
index 22330c9..d3a1fb7 100644
--- a/src/oat/runtime/x86/runtime_support_x86.S
+++ b/src/oat/runtime/x86/runtime_support_x86.S
@@ -307,6 +307,7 @@
 DEFINE_FUNCTION art_portable_resolution_trampoline
     PUSH ebp                      // stash %ebp
     movl %esp, %ebp               // save %esp
+    .cfi_def_cfa_register ebp
     subl LITERAL(8), %esp         // align stack
     movl 8(%ebp), %eax            // load the called method* into %eax
     leal 8(%ebp), %edx            // put the called method* address in %edx
@@ -314,7 +315,9 @@
     PUSH edx                      // pass called method* address
     PUSH eax                      // pass method*
     call SYMBOL(artPortableResolutionTrampoline)  // (method_idx, sp, Thread*)
-    leave                         // restore the stack
+    leave                         // restore the stack and %ebp
+    .cfi_def_cfa esp, 4
+    .cfi_restore ebp
     cmpl LITERAL(0), %eax         // check if returned method code is null
     je resolve_fail               // if null, jump to return to handle
     jmp *%eax                     // otherwise, tail call to intended method
@@ -330,11 +333,13 @@
     movl %esp, %ecx               // save stack pointer
     PUSH eax                      // align stack
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
+    .cfi_adjust_cfa_offset 4
     PUSH ecx                      // pass stack pointer
     PUSH eax                      // pass method*
     call SYMBOL(artQuickResolutionTrampoline)  // (method_idx, sp, Thread*)
     movl %eax, %edi               // save returned code pointer in %edi
     addl LITERAL(16), %esp        // pop arguments
+    .cfi_adjust_cfa_offset -16
     POP eax                       // restore registers
     POP ecx
     POP edx
@@ -1098,6 +1103,57 @@
 END_FUNCTION art_quick_deoptimize
 
     /*
+     * Portable abstract method error stub. method* is at %esp + 4 on entry.
+     */
+DEFINE_FUNCTION art_portable_abstract_method_error_stub
+    PUSH ebp
+    movl %esp, %ebp               // Remember SP.
+    .cfi_def_cfa_register ebp
+    subl LITERAL(12), %esp        // Align stack.
+    PUSH esp                      // Pass sp (not used).
+    pushl %fs:THREAD_SELF_OFFSET  // Pass Thread::Current().
+    pushl 8(%ebp)                 // Pass Method*.
+    call SYMBOL(artThrowAbstractMethodErrorFromCode)  // (Method*, Thread*, SP)
+    leave                         // Restore the stack and %ebp.
+    .cfi_def_cfa esp, 4
+    .cfi_restore ebp
+    ret                           // Return to caller to handle pending exception.
+END_FUNCTION art_portable_abstract_method_error_stub
+
+    /*
+     * Quick abstract method error stub. %eax contains method* on entry.
+     */
+DEFINE_FUNCTION art_quick_abstract_method_error_stub
+    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
+    movl %esp, %ecx               // Remember SP.
+    PUSH eax                      // Align frame.
+    PUSH ecx                      // Pass SP for Method*.
+    pushl %fs:THREAD_SELF_OFFSET  // Pass Thread::Current().
+    .cfi_adjust_cfa_offset 4
+    PUSH eax                      // Pass Method*.
+    call SYMBOL(artThrowAbstractMethodErrorFromCode)  // (Method*, Thread*, SP)
+    int3                          // Unreachable.
+END_FUNCTION art_quick_abstract_method_error_stub
+
+    /*
+     * Portable resolution trampoline.
+     */
+DEFINE_FUNCTION art_jni_dlsym_lookup_stub
+    subl LITERAL(8), %esp         // align stack
+    .cfi_adjust_cfa_offset 8
+    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
+    .cfi_adjust_cfa_offset 4
+    call SYMBOL(artFindNativeMethod)  // (Thread*)
+    addl LITERAL(12), %esp        // restore the stack
+    .cfi_adjust_cfa_offset -12
+    cmpl LITERAL(0), %eax         // check if returned method code is null
+    je no_native_code_found       // if null, jump to return to handle
+    jmp *%eax                     // otherwise, tail call to intended method
+no_native_code_found:
+    ret
+END_FUNCTION art_jni_dlsym_lookup_stub
+
+    /*
      * String's indexOf.
      *
      * On entry:
diff --git a/src/oat/runtime/x86/stub_x86.cc b/src/oat/runtime/x86/stub_x86.cc
deleted file mode 100644
index 3f85b28..0000000
--- a/src/oat/runtime/x86/stub_x86.cc
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "jni_internal.h"
-#include "mirror/array.h"
-#include "mirror/object-inl.h"
-#include "oat/runtime/oat_support_entrypoints.h"
-#include "oat/runtime/stub.h"
-#include "oat/utils/x86/assembler_x86.h"
-#include "stack_indirect_reference_table.h"
-#include "sirt_ref.h"
-
-#define __ assembler->
-
-namespace art {
-namespace x86 {
-
-typedef void (*ThrowAme)(mirror::AbstractMethod*, Thread*);
-
-mirror::ByteArray* CreateAbstractMethodErrorStub() {
-  UniquePtr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
-
-#if !defined(ART_USE_PORTABLE_COMPILER)
-  // Set up the callee save frame to conform with Runtime::CreateCalleeSaveMethod(kSaveAll)
-
-  // return address
-  __ pushl(EDI);
-  __ pushl(ESI);
-  __ pushl(EBP);
-  __ pushl(Immediate(0));
-  __ pushl(Immediate(0));
-  __ pushl(Immediate(0));
-  __ pushl(Immediate(0));  // <-- callee save Method* to go here
-  __ movl(ECX, ESP);       // save ESP
-  __ pushl(Immediate(0));  // align frame
-  __ pushl(ECX);           // pass ESP for Method*
-  __ fs()->pushl(Address::Absolute(Thread::SelfOffset()));  // Thread*
-  __ pushl(EAX);           // pass Method*
-
-  // Call to throw AbstractMethodError.
-  __ Call(ThreadOffset(ENTRYPOINT_OFFSET(pThrowAbstractMethodErrorFromCode)),
-          X86ManagedRegister::FromCpuRegister(ECX));
-
-  // Call never returns.
-  __ int3();
-#else // ART_USE_PORTABLE_COMPILER
-  __ pushl(EBP);
-  __ movl(EBP, ESP);          // save ESP
-  __ subl(ESP, Immediate(12));  // Align stack
-  __ pushl(ESP);  // pass sp (not use)
-  __ fs()->pushl(Address::Absolute(Thread::SelfOffset()));  // pass thread*
-  __ pushl(Address(EBP, 8));  // pass method
-  // Call to throw AbstractMethodError.
-  __ Call(ThreadOffset(ENTRYPOINT_OFFSET(pThrowAbstractMethodErrorFromCode)),
-          X86ManagedRegister::FromCpuRegister(ECX));
-  __ leave();
-  // Return to caller who will handle pending exception.
-  __ ret();
-#endif // ART_USE_PORTABLE_COMPILER
-
-  assembler->EmitSlowPaths();
-
-  size_t cs = assembler->CodeSize();
-  Thread* self = Thread::Current();
-  SirtRef<mirror::ByteArray> abstract_stub(self, mirror::ByteArray::Alloc(self, cs));
-  CHECK(abstract_stub.get() != NULL);
-  MemoryRegion code(abstract_stub->GetData(), abstract_stub->GetLength());
-  assembler->FinalizeInstructions(code);
-
-  return abstract_stub.get();
-}
-
-mirror::ByteArray* CreateJniDlsymLookupStub() {
-  UniquePtr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
-
-  // Pad stack to ensure 16-byte alignment
-  __ pushl(Immediate(0));
-  __ pushl(Immediate(0));
-  __ fs()->pushl(Address::Absolute(Thread::SelfOffset()));  // Thread*
-
-  __ Call(ThreadOffset(ENTRYPOINT_OFFSET(pFindNativeMethod)),
-          X86ManagedRegister::FromCpuRegister(ECX));
-
-  __ addl(ESP, Immediate(12));
-
-  Label no_native_code_found;  // forward declaration
-  __ cmpl(EAX, Immediate(0));
-  __ j(kEqual, &no_native_code_found);
-
-  __ jmp(EAX);  // Tail call into native code
-
-  __ Bind(&no_native_code_found);
-  __ ret(); // return to caller to handle exception
-
-  assembler->EmitSlowPaths();
-
-  size_t cs = assembler->CodeSize();
-  Thread* self = Thread::Current();
-  SirtRef<mirror::ByteArray> jni_stub(self, mirror::ByteArray::Alloc(self, cs));
-  CHECK(jni_stub.get() != NULL);
-  MemoryRegion code(jni_stub->GetData(), jni_stub->GetLength());
-  assembler->FinalizeInstructions(code);
-
-  return jni_stub.get();
-}
-
-} // namespace x86
-} // namespace art
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 62af7a9..353abca 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -82,8 +82,6 @@
 }
 
 const char* image_roots_descriptions_[] = {
-  "kJniStubArray",
-  "kAbstractMethodErrorStubArray",
   "kResolutionMethod",
   "kCalleeSaveMethod",
   "kRefsOnlySaveMethod",
diff --git a/src/runtime.cc b/src/runtime.cc
index b336156..25d26b8 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -82,8 +82,6 @@
       signal_catcher_(NULL),
       java_vm_(NULL),
       pre_allocated_OutOfMemoryError_(NULL),
-      jni_stub_array_(NULL),
-      abstract_method_error_stub_array_(NULL),
       resolution_method_(NULL),
       system_class_loader_(NULL),
       threads_being_born_(0),
@@ -1065,8 +1063,6 @@
   if (pre_allocated_OutOfMemoryError_ != NULL) {
     visitor(pre_allocated_OutOfMemoryError_, arg);
   }
-  visitor(jni_stub_array_, arg);
-  visitor(abstract_method_error_stub_array_, arg);
   visitor(resolution_method_, arg);
   for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
     visitor(callee_save_methods_[i], arg);
@@ -1090,19 +1086,6 @@
   VisitNonConcurrentRoots(visitor, arg);
 }
 
-void Runtime::SetJniDlsymLookupStub(mirror::ByteArray* jni_stub_array) {
-  CHECK(jni_stub_array != NULL)  << " jni_stub_array=" << jni_stub_array;
-  CHECK(jni_stub_array_ == NULL || jni_stub_array_ == jni_stub_array)
-      << "jni_stub_array_=" << jni_stub_array_ << " jni_stub_array=" << jni_stub_array;
-  jni_stub_array_ = jni_stub_array;
-}
-
-void Runtime::SetAbstractMethodErrorStubArray(mirror::ByteArray* abstract_method_error_stub_array) {
-  CHECK(abstract_method_error_stub_array != NULL);
-  CHECK(abstract_method_error_stub_array_ == NULL || abstract_method_error_stub_array_ == abstract_method_error_stub_array);
-  abstract_method_error_stub_array_ = abstract_method_error_stub_array;
-}
-
 mirror::AbstractMethod* Runtime::CreateResolutionMethod() {
   mirror::Class* method_class = mirror::AbstractMethod::GetMethodClass();
   Thread* self = Thread::Current();
diff --git a/src/runtime.h b/src/runtime.h
index 93cffbe..c7ccda1 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -242,28 +242,6 @@
   void VisitNonConcurrentRoots(RootVisitor* visitor, void* arg)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool HasJniDlsymLookupStub() const {
-    return jni_stub_array_ != NULL;
-  }
-
-  mirror::ByteArray* GetJniDlsymLookupStub() const {
-    CHECK(HasJniDlsymLookupStub());
-    return jni_stub_array_;
-  }
-
-  void SetJniDlsymLookupStub(mirror::ByteArray* jni_stub_array);
-
-  bool HasAbstractMethodErrorStubArray() const {
-    return abstract_method_error_stub_array_ != NULL;
-  }
-
-  mirror::ByteArray* GetAbstractMethodErrorStubArray() const {
-    CHECK(abstract_method_error_stub_array_ != NULL);
-    return abstract_method_error_stub_array_;
-  }
-
-  void SetAbstractMethodErrorStubArray(mirror::ByteArray* abstract_method_error_stub_array);
-
   // Returns a special method that calls into a trampoline for runtime method resolution
   mirror::AbstractMethod* GetResolutionMethod() const {
     CHECK(HasResolutionMethod());
@@ -397,10 +375,6 @@
 
   mirror::Throwable* pre_allocated_OutOfMemoryError_;
 
-  mirror::ByteArray* jni_stub_array_;
-
-  mirror::ByteArray* abstract_method_error_stub_array_;
-
   mirror::AbstractMethod* callee_save_methods_[kLastCalleeSaveType];
 
   mirror::AbstractMethod* resolution_method_;
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 2bab323..1c39214 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -31,8 +31,11 @@
 #include "thread.h"
 
 extern "C" void art_interpreter_invoke_handler();
+extern "C" void art_jni_dlsym_lookup_stub();
+extern "C" void art_portable_abstract_method_error_stub();
 extern "C" void art_portable_proxy_invoke_handler();
 extern "C" void art_portable_resolution_trampoline();
+extern "C" void art_quick_abstract_method_error_stub();
 extern "C" void art_quick_deoptimize();
 extern "C" void art_quick_instrumentation_entry_from_code(void*);
 extern "C" void art_quick_instrumentation_exit_from_code();
@@ -356,9 +359,29 @@
 #else
   return GetQuickResolutionTrampoline();
 #endif
+}
+
+static inline void* GetPortableAbstractMethodErrorStub() {
+  return reinterpret_cast<void*>(art_portable_abstract_method_error_stub);
+}
+
+static inline void* GetQuickAbstractMethodErrorStub() {
+  return reinterpret_cast<void*>(art_quick_abstract_method_error_stub);
+}
+
+// Return address of abstract method error stub for defined compiler.
+static inline void* GetAbstractMethodErrorStub() {
+#if defined(ART_USE_PORTABLE_COMPILER)
+  return GetPortableAbstractMethodErrorStub();
+#else
+  return GetQuickAbstractMethodErrorStub();
+#endif
+}
+
+static inline void* GetJniDlsymLookupStub() {
+  return reinterpret_cast<void*>(art_jni_dlsym_lookup_stub);
+}
 
 }  // namespace art
 
-}
-
 #endif  // ART_SRC_RUNTIME_SUPPORT_H_
diff --git a/src/thread.cc b/src/thread.cc
index 7021771..8487078 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -1613,7 +1613,6 @@
   ENTRY_POINT_INFO(pGetObjInstance),
   ENTRY_POINT_INFO(pGetObjStatic),
   ENTRY_POINT_INFO(pHandleFillArrayDataFromCode),
-  ENTRY_POINT_INFO(pFindNativeMethod),
   ENTRY_POINT_INFO(pJniMethodStart),
   ENTRY_POINT_INFO(pJniMethodStartSynchronized),
   ENTRY_POINT_INFO(pJniMethodEnd),
@@ -1655,7 +1654,6 @@
   ENTRY_POINT_INFO(pCheckSuspendFromCode),
   ENTRY_POINT_INFO(pTestSuspendFromCode),
   ENTRY_POINT_INFO(pDeliverException),
-  ENTRY_POINT_INFO(pThrowAbstractMethodErrorFromCode),
   ENTRY_POINT_INFO(pThrowArrayBoundsFromCode),
   ENTRY_POINT_INFO(pThrowDivZeroFromCode),
   ENTRY_POINT_INFO(pThrowNoSuchMethodFromCode),