am 30e2ea4a: Move art to use dalvik names for .oat files

* commit '30e2ea4a701d53f28431041af68dc0669e60c569':
  Move art to use dalvik names for .oat files
diff --git a/build/Android.common.mk b/build/Android.common.mk
index e84667d..f11684e 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -19,6 +19,9 @@
 $(info Enabling ART_SMALL_MODE because of existence of art/SMALL_ART)
 ART_SMALL_MODE := true
 endif
+ifeq ($(WITH_ART_SMALL_MODE), true)
+ART_SMALL_MODE := true
+endif
 
 ART_USE_PORTABLE_COMPILER := false
 ifneq ($(wildcard art/USE_PORTABLE_COMPILER),)
@@ -54,6 +57,7 @@
 	art/src
 
 art_cflags := \
+	-fno-rtti \
 	-O2 \
 	-ggdb3 \
 	-Wall \
@@ -62,13 +66,6 @@
 	-Wstrict-aliasing=3 \
 	-fstrict-aliasing
 
-# Enable thread-safety for GCC 4.6 but not for GCC 4.7 where this feature was removed.
-# Enable GCC 4.6 builds with 'export TARGET_GCC_VERSION_EXP=4.6'
-ifneq ($(filter 4.6 4.6.%, $(TARGET_GCC_VERSION)),)
-  $(info Enabling thread-safety for GCC $(TARGET_GCC_VERSION))
-  art_cflags += -Wthread-safety
-endif
-
 ifeq ($(ART_SMALL_MODE),true)
   art_cflags += -DART_SMALL_MODE=1
 endif
@@ -108,6 +105,22 @@
   ART_TARGET_CFLAGS += -DANDROID_SMP=0
 endif
 
+# Enable thread-safety for GCC 4.6 on the target but not for GCC 4.7 where this feature was removed.
+ifneq ($(filter 4.6 4.6.%, $(TARGET_GCC_VERSION)),)
+  ART_TARGET_CFLAGS += -Wthread-safety
+else
+  # Warn if not using GCC 4.6 for target builds when not doing a top-level or 'mma' build.
+  ifneq ($(ONE_SHOT_MAKEFILE),)
+    # Enable target GCC 4.6 with: export TARGET_GCC_VERSION_EXP=4.6
+    $(info Using target GCC $(TARGET_GCC_VERSION) disables thread-safety checks.)
+  endif
+endif
+# We build with GCC 4.6 on the host.
+ART_HOST_CFLAGS += -Wthread-safety
+
+# Make host builds easier to debug and profile by not omitting the frame pointer.
+ART_HOST_CFLAGS += -fno-omit-frame-pointer
+
 # To use oprofile_android --callgraph, uncomment this and recompile with "mmm art -B -j16"
 # ART_TARGET_CFLAGS += -fno-omit-frame-pointer -marm -mapcs
 
@@ -156,6 +169,8 @@
 	src/compiled_method.cc \
 	src/compiler/driver/compiler_driver.cc \
 	src/compiler/llvm/runtime_support_llvm.cc \
+        src/compiler/stubs/portable/stubs.cc \
+        src/compiler/stubs/quick/stubs.cc \
 	src/debugger.cc \
 	src/dex_file.cc \
 	src/dex_file_verifier.cc \
diff --git a/build/Android.libart-compiler.mk b/build/Android.libart-compiler.mk
index 4452f05..b73a329 100644
--- a/build/Android.libart-compiler.mk
+++ b/build/Android.libart-compiler.mk
@@ -45,7 +45,6 @@
 	src/compiler/dex/quick/x86/utility_x86.cc \
 	src/compiler/dex/portable/mir_to_gbc.cc \
 	src/compiler/dex/mir_dataflow.cc \
-	src/compiler/dex/dataflow_iterator.cc \
 	src/compiler/dex/mir_optimization.cc \
 	src/compiler/dex/frontend.cc \
 	src/compiler/dex/mir_graph.cc \
diff --git a/src/atomic.cc b/src/atomic.cc
index 4efb061..f2a9982 100644
--- a/src/atomic.cc
+++ b/src/atomic.cc
@@ -130,20 +130,9 @@
   } while (__builtin_expect(status != 0, 0));
   return prev == old_value;
 #elif defined(__i386__)
-  // cmpxchg8b implicitly uses %ebx which is also the PIC register.
-  int8_t status;
-  __asm__ __volatile__ (
-      "pushl          %%ebx\n"
-      "movl           (%3), %%ebx\n"
-      "movl           4(%3), %%ecx\n"
-      "lock cmpxchg8b %1\n"
-      "sete           %0\n"
-      "popl           %%ebx"
-      : "=R" (status), "+m" (*addr)
-      : "A"(old_value), "D" (&new_value)
-      : "%ecx"
-      );
-  return status != 0;
+  // The compiler does the right job and works better than inline assembly, especially with -O0
+  // compilation.
+  return __sync_bool_compare_and_swap(addr, old_value, new_value);
 #else
 #error Unexpected architecture
 #endif
diff --git a/src/base/macros.h b/src/base/macros.h
index 8579872..847105d 100644
--- a/src/base/macros.h
+++ b/src/base/macros.h
@@ -136,6 +136,12 @@
 #define ALWAYS_INLINE  __attribute__ ((always_inline))
 #endif
 
+#if defined (__APPLE__)
+#define HOT_ATTR
+#else
+#define HOT_ATTR __attribute__ ((hot))
+#endif
+
 // bionic and glibc both have TEMP_FAILURE_RETRY, but Mac OS' libc doesn't.
 #ifndef TEMP_FAILURE_RETRY
 #define TEMP_FAILURE_RETRY(exp) ({ \
diff --git a/src/base/mutex.h b/src/base/mutex.h
index a3efd5c..a393765 100644
--- a/src/base/mutex.h
+++ b/src/base/mutex.h
@@ -53,7 +53,7 @@
 class ScopedContentionRecorder;
 class Thread;
 
-const bool kDebugLocking = kIsDebugBuild;
+const bool kDebugLocking = true || kIsDebugBuild;
 
 // Base class for all Mutex implementations
 class BaseMutex {
@@ -141,7 +141,7 @@
 
   // Assert that the Mutex is exclusively held by the current thread.
   void AssertExclusiveHeld(const Thread* self) {
-    if (kDebugLocking && !gAborting) {
+    if (kDebugLocking && (gAborting == 0)) {
       CHECK(IsExclusiveHeld(self)) << *this;
     }
   }
@@ -149,7 +149,7 @@
 
   // Assert that the Mutex is not held by the current thread.
   void AssertNotHeldExclusive(const Thread* self) {
-    if (kDebugLocking) {
+    if (kDebugLocking && (gAborting == 0)) {
       CHECK(!IsExclusiveHeld(self)) << *this;
     }
   }
@@ -238,7 +238,7 @@
 
   // Assert the current thread has exclusive access to the ReaderWriterMutex.
   void AssertExclusiveHeld(const Thread* self) {
-    if (kDebugLocking) {
+    if (kDebugLocking & (gAborting == 0)) {
       CHECK(IsExclusiveHeld(self)) << *this;
     }
   }
@@ -246,8 +246,8 @@
 
   // Assert the current thread doesn't have exclusive access to the ReaderWriterMutex.
   void AssertNotExclusiveHeld(const Thread* self) {
-    if (kDebugLocking) {
-      CHECK(!IsExclusiveHeld(self));
+    if (kDebugLocking & (gAborting == 0)) {
+      CHECK(!IsExclusiveHeld(self)) << *this;
     }
   }
   void AssertNotWriterHeld(const Thread* self) { AssertNotExclusiveHeld(self); }
@@ -257,7 +257,7 @@
 
   // Assert the current thread has shared access to the ReaderWriterMutex.
   void AssertSharedHeld(const Thread* self) {
-    if (kDebugLocking) {
+    if (kDebugLocking  & (gAborting == 0)) {
       // TODO: we can only assert this well when self != NULL.
       CHECK(IsSharedHeld(self) || self == NULL) << *this;
     }
@@ -267,7 +267,7 @@
   // Assert the current thread doesn't hold this ReaderWriterMutex either in shared or exclusive
   // mode.
   void AssertNotHeld(const Thread* self) {
-    if (kDebugLocking) {
+    if (kDebugLocking && (gAborting == 0)) {
       CHECK(!IsSharedHeld(self)) << *this;
     }
   }
diff --git a/src/base/stringpiece.cc b/src/base/stringpiece.cc
index 715d964..47140e3 100644
--- a/src/base/stringpiece.cc
+++ b/src/base/stringpiece.cc
@@ -21,12 +21,6 @@
 
 namespace art {
 
-bool operator<(const StringPiece& x, const StringPiece& y) {
-  const int r = memcmp(x.data(), y.data(),
-                       std::min(x.size(), y.size()));
-  return ((r < 0) || ((r == 0) && (x.size() < y.size())));
-}
-
 void StringPiece::CopyToString(std::string* target) const {
   target->assign(ptr_, length_);
 }
diff --git a/src/base/stringpiece.h b/src/base/stringpiece.h
index 193f5f7..3664218 100644
--- a/src/base/stringpiece.h
+++ b/src/base/stringpiece.h
@@ -188,7 +188,11 @@
   return !(x == y);
 }
 
-bool operator<(const StringPiece& x, const StringPiece& y);
+inline bool operator<(const StringPiece& x, const StringPiece& y) {
+  const int r = memcmp(x.data(), y.data(),
+                       std::min(x.size(), y.size()));
+  return ((r < 0) || ((r == 0) && (x.size() < y.size())));
+}
 
 inline bool operator>(const StringPiece& x, const StringPiece& y) {
   return y < x;
diff --git a/src/check_jni.cc b/src/check_jni.cc
index 19f8abf..f4ea235 100644
--- a/src/check_jni.cc
+++ b/src/check_jni.cc
@@ -1215,7 +1215,10 @@
   }
 
   static void FatalError(JNIEnv* env, const char* msg) {
-    CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, msg);
+    // The JNI specification doesn't say it's okay to call FatalError with a pending exception,
+    // but you're about to abort anyway, and it's quite likely that you have a pending exception,
+    // and it's not unimaginable that you don't know that you do. So we allow it.
+    CHECK_JNI_ENTRY(kFlag_ExcepOkay | kFlag_NullableUtf, "Eu", env, msg);
     baseEnv(env)->FatalError(env, msg);
     CHECK_JNI_EXIT_VOID();
   }
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 70c7ff3..77fd5e1 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -44,7 +44,7 @@
 #include "mirror/class.h"
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
-#include "mirror/dex_cache.h"
+#include "mirror/dex_cache-inl.h"
 #include "mirror/field-inl.h"
 #include "mirror/iftable-inl.h"
 #include "mirror/abstract_method.h"
@@ -74,7 +74,9 @@
 
 namespace art {
 
-void artInterpreterToQuickEntry(Thread* self, ShadowFrame* shadow_frame, JValue* result);
+extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh,
+                                           const DexFile::CodeItem* code_item,
+                                           ShadowFrame* shadow_frame, JValue* result);
 
 static void ThrowNoClassDefFoundError(const char* fmt, ...)
     __attribute__((__format__(__printf__, 1, 2)))
@@ -195,12 +197,14 @@
 
 ClassLinker::ClassLinker(InternTable* intern_table)
     // dex_lock_ is recursive as it may be used in stack dumping.
-    : dex_lock_("ClassLinker dex lock", kDefaultMutexLevel, true),
+    : dex_lock_("ClassLinker dex lock", kDefaultMutexLevel),
       class_roots_(NULL),
       array_iftable_(NULL),
       init_done_(false),
       is_dirty_(false),
-      intern_table_(intern_table) {
+      intern_table_(intern_table),
+      portable_resolution_trampoline_(NULL),
+      quick_resolution_trampoline_(NULL) {
   CHECK_EQ(arraysize(class_roots_descriptors_), size_t(kClassRootsMax));
 }
 
@@ -662,22 +666,22 @@
 }
 
 void ClassLinker::RegisterOatFile(const OatFile& oat_file) {
-  MutexLock mu(Thread::Current(), dex_lock_);
+  WriterMutexLock mu(Thread::Current(), dex_lock_);
   RegisterOatFileLocked(oat_file);
 }
 
 void ClassLinker::RegisterOatFileLocked(const OatFile& oat_file) {
-  dex_lock_.AssertHeld(Thread::Current());
-#ifndef NDEBUG
-  for (size_t i = 0; i < oat_files_.size(); ++i) {
-    CHECK_NE(&oat_file, oat_files_[i]) << oat_file.GetLocation();
+  dex_lock_.AssertExclusiveHeld(Thread::Current());
+  if (kIsDebugBuild) {
+    for (size_t i = 0; i < oat_files_.size(); ++i) {
+      CHECK_NE(&oat_file, oat_files_[i]) << oat_file.GetLocation();
+    }
   }
-#endif
   oat_files_.push_back(&oat_file);
 }
 
 OatFile* ClassLinker::OpenOat(const ImageSpace* space) {
-  MutexLock mu(Thread::Current(), dex_lock_);
+  WriterMutexLock mu(Thread::Current(), dex_lock_);
   const Runtime* runtime = Runtime::Current();
   const ImageHeader& image_header = space->GetImageHeader();
   // Grab location but don't use Object::AsString as we haven't yet initialized the roots to
@@ -708,7 +712,7 @@
 }
 
 const OatFile* ClassLinker::FindOpenedOatFileForDexFile(const DexFile& dex_file) {
-  MutexLock mu(Thread::Current(), dex_lock_);
+  ReaderMutexLock mu(Thread::Current(), dex_lock_);
   return FindOpenedOatFileFromDexLocation(dex_file.GetLocation());
 }
 
@@ -724,10 +728,9 @@
   return NULL;
 }
 
-static const DexFile* FindDexFileInOatLocation(const std::string& dex_location,
-                                               uint32_t dex_location_checksum,
-                                               const std::string& oat_location)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+const DexFile* ClassLinker::FindDexFileInOatLocation(const std::string& dex_location,
+                                                     uint32_t dex_location_checksum,
+                                                     const std::string& oat_location) {
   UniquePtr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, NULL));
   if (oat_file.get() == NULL) {
     return NULL;
@@ -748,13 +751,13 @@
   if (oat_dex_file->GetDexFileLocationChecksum() != dex_location_checksum) {
     return NULL;
   }
-  runtime->GetClassLinker()->RegisterOatFile(*oat_file.release());
+  RegisterOatFileLocked(*oat_file.release());
   return oat_dex_file->OpenDexFile();
 }
 
 const DexFile* ClassLinker::FindOrCreateOatFileForDexLocation(const std::string& dex_location,
                                                               const std::string& oat_location) {
-  MutexLock mu(Thread::Current(), dex_lock_);
+  WriterMutexLock mu(Thread::Current(), dex_lock_);
   return FindOrCreateOatFileForDexLocationLocked(dex_location, oat_location);
 }
 
@@ -856,7 +859,7 @@
 }
 
 const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(const std::string& dex_location) {
-  MutexLock mu(Thread::Current(), dex_lock_);
+  WriterMutexLock mu(Thread::Current(), dex_lock_);
 
   const OatFile* open_oat_file = FindOpenedOatFileFromDexLocation(dex_location);
   if (open_oat_file != NULL) {
@@ -923,7 +926,7 @@
 }
 
 const OatFile* ClassLinker::FindOatFileFromOatLocation(const std::string& oat_location) {
-  MutexLock mu(Thread::Current(), dex_lock_);
+  ReaderMutexLock mu(Thread::Current(), dex_lock_);
   return FindOatFileFromOatLocationLocked(oat_location);
 }
 
@@ -951,6 +954,8 @@
   CHECK_EQ(oat_file->GetOatHeader().GetImageFileLocationOatChecksum(), 0U);
   CHECK_EQ(oat_file->GetOatHeader().GetImageFileLocationOatDataBegin(), 0U);
   CHECK(oat_file->GetOatHeader().GetImageFileLocation().empty());
+  portable_resolution_trampoline_ = oat_file->GetOatHeader().GetPortableResolutionTrampoline();
+  quick_resolution_trampoline_ = oat_file->GetOatHeader().GetQuickResolutionTrampoline();
   mirror::Object* dex_caches_object = space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches);
   mirror::ObjectArray<mirror::DexCache>* dex_caches =
       dex_caches_object->AsObjectArray<mirror::DexCache>();
@@ -1037,17 +1042,14 @@
     return;
   }
 
-  // Check if object is a method without its code set and point it to the resolution trampoline.
+  // Set entry points to interpreter for methods in interpreter only mode.
   if (obj->IsMethod()) {
     mirror::AbstractMethod* method = obj->AsMethod();
-    // Install entry point from interpreter.
-    if (method->GetEntryPointFromCompiledCode() == NULL && !method->IsNative() && !method->IsProxyMethod()) {
-      method->SetEntryPointFromInterpreter(interpreter::EnterInterpreterFromInterpreter);
-    } else {
-      method->SetEntryPointFromInterpreter(artInterpreterToQuickEntry);
-    }
-    if (method->GetEntryPointFromCompiledCode() == NULL) {
-      method->SetEntryPointFromCompiledCode(GetResolutionTrampoline());
+    if (Runtime::Current()->GetInstrumentation()->InterpretOnly() && !method->IsNative()) {
+      method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterEntry);
+      if (method != Runtime::Current()->GetResolutionMethod()) {
+        method->SetEntryPointFromCompiledCode(GetInterpreterEntryPoint());
+      }
     }
   }
 }
@@ -1059,14 +1061,14 @@
   visitor(class_roots_, arg);
   Thread* self = Thread::Current();
   {
-    MutexLock mu(self, dex_lock_);
+    ReaderMutexLock mu(self, dex_lock_);
     for (size_t i = 0; i < dex_caches_.size(); i++) {
       visitor(dex_caches_[i], arg);
     }
   }
 
   {
-    MutexLock mu(self, *Locks::classlinker_classes_lock_);
+    ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
     typedef Table::const_iterator It;  // TODO: C++0x auto
     for (It it = classes_.begin(), end = classes_.end(); it != end; ++it) {
       visitor(it->second, arg);
@@ -1081,7 +1083,7 @@
 }
 
 void ClassLinker::VisitClasses(ClassVisitor* visitor, void* arg) const {
-  MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+  ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
   typedef Table::const_iterator It;  // TODO: C++0x auto
   for (It it = classes_.begin(), end = classes_.end(); it != end; ++it) {
     if (!visitor(it->second, arg)) {
@@ -1608,14 +1610,16 @@
   oat_method.LinkMethod(method.get());
 
   // Install entry point from interpreter.
-  if (method->GetEntryPointFromCompiledCode() == NULL && !method->IsNative() &&
-      !method->IsProxyMethod()) {
-    method->SetEntryPointFromInterpreter(interpreter::EnterInterpreterFromInterpreter);
+  Runtime* runtime = Runtime::Current();
+  bool enter_interpreter = method->GetEntryPointFromCompiledCode() == NULL ||
+                           (runtime->GetInstrumentation()->InterpretOnly() &&
+                           !method->IsNative() && !method->IsProxyMethod());
+  if (enter_interpreter) {
+    method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterEntry);
   } else {
     method->SetEntryPointFromInterpreter(artInterpreterToQuickEntry);
   }
 
-  Runtime* runtime = Runtime::Current();
   if (method->IsAbstract()) {
     method->SetEntryPointFromCompiledCode(GetAbstractMethodErrorStub());
     return;
@@ -1623,7 +1627,7 @@
 
   if (method->IsStatic() && !method->IsConstructor()) {
     // For static methods excluding the class initializer, install the trampoline.
-    method->SetEntryPointFromCompiledCode(GetResolutionTrampoline());
+    method->SetEntryPointFromCompiledCode(GetResolutionTrampoline(runtime->GetClassLinker()));
   }
 
   if (method->IsNative()) {
@@ -1631,8 +1635,8 @@
     method->UnregisterNative(Thread::Current());
   }
 
-  if (method->GetEntryPointFromCompiledCode() == NULL) {
-    // No code? You must mean to go into the interpreter.
+  if (enter_interpreter) {
+    // Set entry point from compiled code if there's no code or in interpreter only mode.
     method->SetEntryPointFromCompiledCode(GetInterpreterEntryPoint());
   }
 
@@ -1807,7 +1811,7 @@
 }
 
 bool ClassLinker::IsDexFileRegisteredLocked(const DexFile& dex_file) const {
-  dex_lock_.AssertHeld(Thread::Current());
+  dex_lock_.AssertSharedHeld(Thread::Current());
   for (size_t i = 0; i != dex_caches_.size(); ++i) {
     if (dex_caches_[i]->GetDexFile() == &dex_file) {
       return true;
@@ -1817,12 +1821,12 @@
 }
 
 bool ClassLinker::IsDexFileRegistered(const DexFile& dex_file) const {
-  MutexLock mu(Thread::Current(), dex_lock_);
+  ReaderMutexLock mu(Thread::Current(), dex_lock_);
   return IsDexFileRegisteredLocked(dex_file);
 }
 
 void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) {
-  dex_lock_.AssertHeld(Thread::Current());
+  dex_lock_.AssertExclusiveHeld(Thread::Current());
   CHECK(dex_cache.get() != NULL) << dex_file.GetLocation();
   CHECK(dex_cache->GetLocation()->Equals(dex_file.GetLocation()));
   dex_caches_.push_back(dex_cache.get());
@@ -1833,7 +1837,7 @@
 void ClassLinker::RegisterDexFile(const DexFile& dex_file) {
   Thread* self = Thread::Current();
   {
-    MutexLock mu(self, dex_lock_);
+    ReaderMutexLock mu(self, dex_lock_);
     if (IsDexFileRegisteredLocked(dex_file)) {
       return;
     }
@@ -1843,7 +1847,7 @@
   // get to a suspend point.
   SirtRef<mirror::DexCache> dex_cache(self, AllocDexCache(self, dex_file));
   {
-    MutexLock mu(self, dex_lock_);
+    WriterMutexLock mu(self, dex_lock_);
     if (IsDexFileRegisteredLocked(dex_file)) {
       return;
     }
@@ -1852,12 +1856,12 @@
 }
 
 void ClassLinker::RegisterDexFile(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) {
-  MutexLock mu(Thread::Current(), dex_lock_);
+  WriterMutexLock mu(Thread::Current(), dex_lock_);
   RegisterDexFileLocked(dex_file, dex_cache);
 }
 
 mirror::DexCache* ClassLinker::FindDexCache(const DexFile& dex_file) const {
-  MutexLock mu(Thread::Current(), dex_lock_);
+  ReaderMutexLock mu(Thread::Current(), dex_lock_);
   // Search assuming unique-ness of dex file.
   for (size_t i = 0; i != dex_caches_.size(); ++i) {
     mirror::DexCache* dex_cache = dex_caches_[i];
@@ -1883,7 +1887,7 @@
 }
 
 void ClassLinker::FixupDexCaches(mirror::AbstractMethod* resolution_method) const {
-  MutexLock mu(Thread::Current(), dex_lock_);
+  ReaderMutexLock mu(Thread::Current(), dex_lock_);
   for (size_t i = 0; i != dex_caches_.size(); ++i) {
     dex_caches_[i]->Fixup(resolution_method);
   }
@@ -2017,15 +2021,16 @@
   CHECK(array_iftable_ != NULL);
   new_class->SetIfTable(array_iftable_);
 
-  // Inherit access flags from the component type.  Arrays can't be
-  // used as a superclass or interface, so we want to add "final"
+  // Inherit access flags from the component type.
+  int access_flags = new_class->GetComponentType()->GetAccessFlags();
+  // Lose any implementation detail flags; in particular, arrays aren't finalizable.
+  access_flags &= kAccJavaFlagsMask;
+  // Arrays can't be used as a superclass or interface, so we want to add "abstract final"
   // and remove "interface".
-  //
-  // Don't inherit any non-standard flags (e.g., kAccFinal)
-  // from component_type.  We assume that the array class does not
-  // override finalize().
-  new_class->SetAccessFlags(((new_class->GetComponentType()->GetAccessFlags() &
-                             ~kAccInterface) | kAccFinal) & kAccJavaFlagsMask);
+  access_flags |= kAccAbstract | kAccFinal;
+  access_flags &= ~kAccInterface;
+
+  new_class->SetAccessFlags(access_flags);
 
   mirror::Class* existing = InsertClass(descriptor, new_class.get(), false);
   if (existing == NULL) {
@@ -2079,7 +2084,7 @@
     LOG(INFO) << "Loaded class " << descriptor << source;
   }
   size_t hash = StringPieceHash()(descriptor);
-  MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+  WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
   Table& classes = image_class ? image_classes_ : classes_;
   mirror::Class* existing = LookupClassLocked(descriptor.data(), klass->GetClassLoader(), hash, classes);
 #ifndef NDEBUG
@@ -2097,7 +2102,7 @@
 
 bool ClassLinker::RemoveClass(const char* descriptor, const mirror::ClassLoader* class_loader) {
   size_t hash = Hash(descriptor);
-  MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+  WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
   typedef Table::iterator It;  // TODO: C++0x auto
   // TODO: determine if its better to search classes_ or image_classes_ first
   ClassHelper kh;
@@ -2125,7 +2130,7 @@
 mirror::Class* ClassLinker::LookupClass(const char* descriptor,
                                         const mirror::ClassLoader* class_loader) {
   size_t hash = Hash(descriptor);
-  MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+  ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
   // TODO: determine if its better to search classes_ or image_classes_ first
   mirror::Class* klass = NULL;
   // Use image class only if the class_loader is null.
@@ -2165,7 +2170,7 @@
 void ClassLinker::LookupClasses(const char* descriptor, std::vector<mirror::Class*>& classes) {
   classes.clear();
   size_t hash = Hash(descriptor);
-  MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+  ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
   typedef Table::const_iterator It;  // TODO: C++0x auto
   // TODO: determine if its better to search classes_ or image_classes_ first
   ClassHelper kh(NULL, this);
@@ -2243,7 +2248,6 @@
   const DexFile& dex_file = *klass->GetDexCache()->GetDexFile();
   mirror::Class::Status oat_file_class_status(mirror::Class::kStatusNotReady);
   bool preverified = VerifyClassUsingOatFile(dex_file, klass, oat_file_class_status);
-  verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure;
   if (oat_file_class_status == mirror::Class::kStatusError) {
     LOG(WARNING) << "Skipping runtime verification of erroneous class " << PrettyDescriptor(klass)
                  << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8();
@@ -2252,9 +2256,11 @@
     klass->SetStatus(mirror::Class::kStatusError);
     return;
   }
+  verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure;
   std::string error_msg;
   if (!preverified) {
-    verifier_failure = verifier::MethodVerifier::VerifyClass(klass, error_msg, Runtime::Current()->IsCompiler());
+    verifier_failure = verifier::MethodVerifier::VerifyClass(klass, error_msg,
+                                                             Runtime::Current()->IsCompiler());
   }
   if (preverified || verifier_failure != verifier::MethodVerifier::kHardFailure) {
     if (!preverified && verifier_failure != verifier::MethodVerifier::kNoFailure) {
@@ -2286,6 +2292,15 @@
     ThrowVerifyError(klass, "%s", error_msg.c_str());
     klass->SetStatus(mirror::Class::kStatusError);
   }
+  if (preverified || verifier_failure == verifier::MethodVerifier::kNoFailure) {
+    // Class is verified so we don't need to do any access check in its methods.
+    // Let the interpreter know it by setting the kAccPreverified flag onto each
+    // method.
+    // Note: we're going here during compilation and at runtime. When we set the
+    // kAccPreverified flag when compiling image classes, the flag is recorded
+    // in the image and is set when loading the image.
+    klass->SetPreverifiedFlagOnAllMethods();
+  }
 }
 
 bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class* klass,
@@ -2499,7 +2514,7 @@
   mirror::DexCache* dex_cache = NULL;
   {
     mirror::ObjectArray<mirror::Class>* resolved_types = proxy_method->GetDexCacheResolvedTypes();
-    MutexLock mu(Thread::Current(), dex_lock_);
+    ReaderMutexLock mu(Thread::Current(), dex_lock_);
     for (size_t i = 0; i != dex_caches_.size(); ++i) {
       if (dex_caches_[i]->GetResolvedTypes() == resolved_types) {
         dex_cache = dex_caches_[i];
@@ -3880,7 +3895,7 @@
   // lock held, because it might need to resolve a field's type, which would try to take the lock.
   std::vector<mirror::Class*> all_classes;
   {
-    MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+    ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
     typedef Table::const_iterator It;  // TODO: C++0x auto
     for (It it = classes_.begin(), end = classes_.end(); it != end; ++it) {
       all_classes.push_back(it->second);
@@ -3896,13 +3911,13 @@
 }
 
 void ClassLinker::DumpForSigQuit(std::ostream& os) const {
-  MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+  ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
   os << "Loaded classes: " << image_classes_.size() << " image classes; "
      << classes_.size() << " allocated classes\n";
 }
 
 size_t ClassLinker::NumLoadedClasses() const {
-  MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+  ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
   return classes_.size() + image_classes_.size();
 }
 
diff --git a/src/class_linker.h b/src/class_linker.h
index d41373c..e0f297d 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -240,7 +240,7 @@
       LOCKS_EXCLUDED(dex_lock_);
 
   const OatFile* FindOatFileFromOatLocationLocked(const std::string& location)
-      EXCLUSIVE_LOCKS_REQUIRED(dex_lock_);
+      SHARED_LOCKS_REQUIRED(dex_lock_);
 
   // Finds the oat file for a dex location, generating the oat file if
   // it is missing or out of date. Returns the DexFile from within the
@@ -334,6 +334,14 @@
     is_dirty_ = true;
   }
 
+  const void* GetPortableResolutionTrampoline() const {
+    return portable_resolution_trampoline_;
+  }
+
+  const void* GetQuickResolutionTrampoline() const {
+    return quick_resolution_trampoline_;
+  }
+
  private:
   explicit ClassLinker(InternTable*);
 
@@ -420,7 +428,7 @@
   void RegisterDexFileLocked(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache)
       EXCLUSIVE_LOCKS_REQUIRED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool IsDexFileRegisteredLocked(const DexFile& dex_file) const EXCLUSIVE_LOCKS_REQUIRED(dex_lock_);
+  bool IsDexFileRegisteredLocked(const DexFile& dex_file) const SHARED_LOCKS_REQUIRED(dex_lock_);
   void RegisterOatFileLocked(const OatFile& oat_file) EXCLUSIVE_LOCKS_REQUIRED(dex_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(dex_lock_);
 
@@ -489,10 +497,15 @@
       LOCKS_EXCLUDED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const OatFile* FindOpenedOatFileFromDexLocation(const std::string& dex_location)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, dex_lock_);
+  const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location)
+      SHARED_LOCKS_REQUIRED(dex_lock_);
+  const DexFile* FindDexFileInOatLocation(const std::string& dex_location,
+                                          uint32_t dex_location_checksum,
+                                          const std::string& oat_location)
       EXCLUSIVE_LOCKS_REQUIRED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location)
-      EXCLUSIVE_LOCKS_REQUIRED(dex_lock_);
+
   const DexFile* VerifyAndOpenDexFileFromOatFile(const OatFile* oat_file,
                                                  const std::string& dex_location,
                                                  uint32_t dex_location_checksum)
@@ -508,7 +521,7 @@
 
   std::vector<const DexFile*> boot_class_path_;
 
-  mutable Mutex dex_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  mutable ReaderWriterMutex dex_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   std::vector<mirror::DexCache*> dex_caches_ GUARDED_BY(dex_lock_);
   std::vector<const OatFile*> oat_files_ GUARDED_BY(dex_lock_);
 
@@ -522,8 +535,7 @@
 
   mirror::Class* LookupClassLocked(const char* descriptor, const mirror::ClassLoader* class_loader,
                                    size_t hash, const Table& classes)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::classlinker_classes_lock_);
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::classlinker_classes_lock_);
 
   // indexes into class_roots_.
   // needs to be kept in sync with class_roots_descriptors_.
@@ -595,6 +607,9 @@
 
   InternTable* intern_table_;
 
+  const void* portable_resolution_trampoline_;
+  const void* quick_resolution_trampoline_;
+
   friend class CommonTest;
   friend class ImageWriter;  // for GetClassRoots
   friend class ObjectTest;
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 73bdc61..4540c01 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -90,6 +90,7 @@
     EXPECT_TRUE(primitive->GetVTable() == NULL);
     EXPECT_EQ(0, primitive->GetIfTableCount());
     EXPECT_TRUE(primitive->GetIfTable() == NULL);
+    EXPECT_EQ(kAccPublic | kAccFinal | kAccAbstract, primitive->GetAccessFlags());
   }
 
   void AssertArrayClass(const std::string& array_descriptor,
@@ -100,6 +101,7 @@
     ClassHelper array_component_ch(array->GetComponentType());
     EXPECT_STREQ(component_type.c_str(), array_component_ch.GetDescriptor());
     EXPECT_EQ(class_loader, array->GetClassLoader());
+    EXPECT_EQ(kAccFinal | kAccAbstract, (array->GetAccessFlags() & (kAccFinal | kAccAbstract)));
     AssertArrayClass(array_descriptor, array);
   }
 
diff --git a/src/common_test.h b/src/common_test.h
index 3baa77c..0c171a8 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -346,9 +346,11 @@
       }
     }
     class_linker_->FixupDexCaches(runtime_->GetResolutionMethod());
-    image_classes_.reset(new std::set<std::string>);
-    compiler_driver_.reset(new CompilerDriver(compiler_backend, instruction_set, true, 2, false,
-                                              image_classes_.get(), true, true));
+    compiler_driver_.reset(new CompilerDriver(compiler_backend, instruction_set,
+                                              true, new CompilerDriver::DescriptorSet,
+                                              2, false, true, true));
+    // We typically don't generate an image in unit tests, disable this optimization by default.
+    compiler_driver_->SetSupportBootImageFixup(false);
 
     // Create the heap thread pool so that the GC runs in parallel for tests. Normally, the thread
     // pool is created by the runtime.
@@ -389,7 +391,6 @@
     (*icu_cleanup_fn)();
 
     compiler_driver_.reset();
-    image_classes_.reset();
     STLDeleteElements(&opened_dex_files_);
 
     Runtime::Current()->GetHeap()->VerifyHeap();  // Check for heap corruption after the test
@@ -522,7 +523,6 @@
   // Owned by the runtime
   ClassLinker* class_linker_;
   UniquePtr<CompilerDriver> compiler_driver_;
-  UniquePtr<std::set<std::string> > image_classes_;
 
  private:
   std::vector<const DexFile*> opened_dex_files_;
diff --git a/src/compiler/dex/arena_bit_vector.cc b/src/compiler/dex/arena_bit_vector.cc
index 6f664e5..1fbf774 100644
--- a/src/compiler/dex/arena_bit_vector.cc
+++ b/src/compiler/dex/arena_bit_vector.cc
@@ -113,18 +113,6 @@
   }
 }
 
-// Are we equal to another bit vector?  Note: expandability attributes must also match.
-bool ArenaBitVector::Equal(const ArenaBitVector* src) {
-  if (storage_size_ != src->GetStorageSize() ||
-      expandable_ != src->IsExpandable())
-    return false;
-
-  for (unsigned int idx = 0; idx < storage_size_; idx++) {
-    if (storage_[idx] != src->GetRawStorageWord(idx)) return false;
-  }
-  return true;
-}
-
 // Count the number of bits that are set.
 int ArenaBitVector::NumSetBits()
 {
@@ -136,43 +124,6 @@
   return count;
 }
 
-// Return the position of the next set bit.  -1 means end-of-element reached.
-// TUNING: Hot function.
-int ArenaBitVector::Iterator::Next()
-{
-  // Did anything obviously change since we started?
-  DCHECK_EQ(bit_size_, p_bits_->GetStorageSize() * sizeof(uint32_t) * 8);
-  DCHECK_EQ(bit_storage_, p_bits_->GetRawStorage());
-
-  if (bit_index_ >= bit_size_) return -1;
-
-  uint32_t word_index = bit_index_ >> 5;
-  uint32_t end_word_index = bit_size_ >> 5;
-  uint32_t word = bit_storage_[word_index++];
-
-  // Mask out any bits in the first word we've already considered.
-  word &= ~((1 << (bit_index_ & 0x1f))-1);
-
-  for (; word_index <= end_word_index;) {
-    uint32_t bit_pos = bit_index_ & 0x1f;
-    if (word == 0) {
-      bit_index_ += (32 - bit_pos);
-      word = bit_storage_[word_index++];
-      continue;
-    }
-    for (; bit_pos < 32; bit_pos++) {
-      if (word & (1 << bit_pos)) {
-        bit_index_++;
-        return bit_index_ - 1;
-      }
-      bit_index_++;
-    }
-    word = bit_storage_[word_index++];
-  }
-  bit_index_ = bit_size_;
-  return -1;
-}
-
 /*
  * Mark specified number of bits as "set". Cannot set all bits like ClearAll
  * since there might be unused bits - setting those to one will confuse the
diff --git a/src/compiler/dex/arena_bit_vector.h b/src/compiler/dex/arena_bit_vector.h
index f5c471c..a950e82 100644
--- a/src/compiler/dex/arena_bit_vector.h
+++ b/src/compiler/dex/arena_bit_vector.h
@@ -39,7 +39,33 @@
             bit_index_(0),
             bit_size_(p_bits_->storage_size_ * sizeof(uint32_t) * 8) {};
 
-        int Next();  // Returns -1 when no next.
+        // Return the position of the next set bit.  -1 means end-of-element reached.
+        int Next() {
+          // Did anything obviously change since we started?
+          DCHECK_EQ(bit_size_, p_bits_->GetStorageSize() * sizeof(uint32_t) * 8);
+          DCHECK_EQ(bit_storage_, p_bits_->GetRawStorage());
+
+          if (bit_index_ >= bit_size_) return -1;
+
+          uint32_t word_index = bit_index_ / 32;
+          uint32_t word = bit_storage_[word_index];
+          // Mask out any bits in the first word we've already considered.
+          word >>= bit_index_ & 0x1f;
+          if (word == 0) {
+            bit_index_ &= ~0x1f;
+            do {
+              word_index++;
+              if ((word_index * 32) >= bit_size_) {
+                bit_index_ = bit_size_;
+                return -1;
+              }
+              word = bit_storage_[word_index];
+              bit_index_ += 32;
+            } while (word == 0);
+          }
+          bit_index_ += CTZ(word) + 1;
+          return bit_index_ - 1;
+        }
 
         static void* operator new(size_t size, ArenaAllocator* arena) {
           return arena->NewMem(sizeof(ArenaBitVector::Iterator), true,
@@ -73,13 +99,19 @@
     void Copy(ArenaBitVector* src);
     void Intersect(const ArenaBitVector* src2);
     void Union(const ArenaBitVector* src);
-    bool Equal(const ArenaBitVector* src);
+    // Are we equal to another bit vector?  Note: expandability attributes must also match.
+    bool Equal(const ArenaBitVector* src) {
+      return (storage_size_ == src->GetStorageSize()) &&
+        (expandable_ == src->IsExpandable()) &&
+        (memcmp(storage_, src->GetRawStorage(), storage_size_ * 4) == 0);
+    }
     int NumSetBits();
 
     uint32_t GetStorageSize() const { return storage_size_; }
     bool IsExpandable() const { return expandable_; }
     uint32_t GetRawStorageWord(size_t idx) const { return storage_[idx]; }
     uint32_t* GetRawStorage() { return storage_; }
+    const uint32_t* GetRawStorage() const { return storage_; }
 
   private:
     ArenaAllocator* const arena_;
diff --git a/src/compiler/dex/dataflow_iterator-inl.h b/src/compiler/dex/dataflow_iterator-inl.h
new file mode 100644
index 0000000..b20004d
--- /dev/null
+++ b/src/compiler/dex/dataflow_iterator-inl.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2013 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_COMPILER_DEX_DATAFLOW_ITERATOR_INL_H_
+#define ART_SRC_COMPILER_DEX_DATAFLOW_ITERATOR_INL_H_
+
+#include "dataflow_iterator.h"
+
+namespace art {
+
+inline BasicBlock* DataflowIterator::NextBody(bool had_change) {
+  changed_ |= had_change;
+  BasicBlock* res = NULL;
+  if (reverse_) {
+    if (is_iterative_ && changed_ && (idx_ < 0)) {
+      idx_ = start_idx_;
+      changed_ = false;
+    }
+    if (idx_ >= 0) {
+      int bb_id = block_id_list_->Get(idx_--);
+      res = mir_graph_->GetBasicBlock(bb_id);
+    }
+  } else {
+    if (is_iterative_ && changed_ && (idx_ >= end_idx_)) {
+      idx_ = start_idx_;
+      changed_ = false;
+    }
+    if (idx_ < end_idx_) {
+      int bb_id = block_id_list_->Get(idx_++);
+      res = mir_graph_->GetBasicBlock(bb_id);
+    }
+  }
+  return res;
+}
+
+// AllNodes uses the existing GrowableArray iterator, so use different NextBody().
+inline BasicBlock* AllNodesIterator::NextBody(bool had_change) {
+  changed_ |= had_change;
+  BasicBlock* res = NULL;
+  bool keep_looking = true;
+  while (keep_looking) {
+    res = all_nodes_iterator_->Next();
+    if (is_iterative_ && changed_ && (res == NULL)) {
+      all_nodes_iterator_->Reset();
+      changed_ = false;
+    } else if ((res == NULL) || (!res->hidden)) {
+      keep_looking = false;
+    }
+  }
+  return res;
+}
+
+}  // namespace art
+
+#endif  // ART_SRC_COMPILER_DEX_DATAFLOW_ITERATOR_INL_H_
diff --git a/src/compiler/dex/dataflow_iterator.cc b/src/compiler/dex/dataflow_iterator.cc
deleted file mode 100644
index bb5b969..0000000
--- a/src/compiler/dex/dataflow_iterator.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2013 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 "dataflow_iterator.h"
-
-namespace art {
-
-  BasicBlock* DataflowIterator::NextBody(bool had_change) {
-    changed_ |= had_change;
-    BasicBlock* res = NULL;
-    if (reverse_) {
-      if (is_iterative_ && changed_ && (idx_ < 0)) {
-        idx_ = start_idx_;
-        changed_ = false;
-      }
-      if (idx_ >= 0) {
-        int bb_id = block_id_list_->Get(idx_--);
-        res = mir_graph_->GetBasicBlock(bb_id);
-      }
-    } else {
-      if (is_iterative_ && changed_ && (idx_ >= end_idx_)) {
-        idx_ = start_idx_;
-        changed_ = false;
-      }
-      if (idx_ < end_idx_) {
-        int bb_id = block_id_list_->Get(idx_++);
-        res = mir_graph_->GetBasicBlock(bb_id);
-      }
-    }
-    return res;
-  }
-
-  // AllNodes uses the existing GrowableArray iterator, so use different NextBody().
-  BasicBlock* AllNodesIterator::NextBody(bool had_change) {
-    changed_ |= had_change;
-    BasicBlock* res = NULL;
-    bool keep_looking = true;
-    while (keep_looking) {
-      res = all_nodes_iterator_->Next();
-      if (is_iterative_ && changed_ && (res == NULL)) {
-        all_nodes_iterator_->Reset();
-        changed_ = false;
-      } else if ((res == NULL) || (!res->hidden)) {
-        keep_looking = false;
-      }
-    }
-    return res;
-  }
-
-}  // namespace art
diff --git a/src/compiler/dex/dataflow_iterator.h b/src/compiler/dex/dataflow_iterator.h
index a4b38bd..12cbf9c 100644
--- a/src/compiler/dex/dataflow_iterator.h
+++ b/src/compiler/dex/dataflow_iterator.h
@@ -71,7 +71,7 @@
             idx_(0),
             changed_(false) {}
 
-      virtual BasicBlock* NextBody(bool had_change);
+      virtual BasicBlock* NextBody(bool had_change) ALWAYS_INLINE;
 
       MIRGraph* const mir_graph_;
       const bool is_iterative_;
@@ -86,7 +86,6 @@
 
   class ReachableNodesIterator : public DataflowIterator {
     public:
-
       ReachableNodesIterator(MIRGraph* mir_graph, bool is_iterative)
           : DataflowIterator(mir_graph, is_iterative, 0,
                              mir_graph->GetNumReachableBlocks(), false) {
@@ -97,7 +96,6 @@
 
   class PreOrderDfsIterator : public DataflowIterator {
     public:
-
       PreOrderDfsIterator(MIRGraph* mir_graph, bool is_iterative)
           : DataflowIterator(mir_graph, is_iterative, 0,
                              mir_graph->GetNumReachableBlocks(), false) {
@@ -119,7 +117,6 @@
 
   class ReversePostOrderDfsIterator : public DataflowIterator {
     public:
-
       ReversePostOrderDfsIterator(MIRGraph* mir_graph, bool is_iterative)
           : DataflowIterator(mir_graph, is_iterative,
                              mir_graph->GetNumReachableBlocks() -1, 0, true) {
@@ -130,7 +127,6 @@
 
   class PostOrderDOMIterator : public DataflowIterator {
     public:
-
       PostOrderDOMIterator(MIRGraph* mir_graph, bool is_iterative)
           : DataflowIterator(mir_graph, is_iterative, 0,
                              mir_graph->GetNumReachableBlocks(), false) {
@@ -141,18 +137,17 @@
 
   class AllNodesIterator : public DataflowIterator {
     public:
-
       AllNodesIterator(MIRGraph* mir_graph, bool is_iterative)
           : DataflowIterator(mir_graph, is_iterative, 0, 0, false) {
         all_nodes_iterator_ =
             new (mir_graph->GetArena()) GrowableArray<BasicBlock*>::Iterator (mir_graph->GetBlockList());
       }
 
-      virtual void Reset() {
+      void Reset() {
         all_nodes_iterator_->Reset();
       }
 
-      virtual BasicBlock* NextBody(bool had_change);
+      BasicBlock* NextBody(bool had_change) ALWAYS_INLINE;
 
     private:
       GrowableArray<BasicBlock*>::Iterator* all_nodes_iterator_;
diff --git a/src/compiler/dex/frontend.cc b/src/compiler/dex/frontend.cc
index ca751ab..e015645 100644
--- a/src/compiler/dex/frontend.cc
+++ b/src/compiler/dex/frontend.cc
@@ -18,7 +18,7 @@
 
 #include "compiler/driver/compiler_driver.h"
 #include "compiler_internals.h"
-#include "dataflow_iterator.h"
+#include "dataflow_iterator-inl.h"
 #if defined(ART_USE_PORTABLE_COMPILER)
 #include "compiler/llvm/llvm_compilation_unit.h"
 #include "compiler/dex/portable/mir_to_gbc.h"
diff --git a/src/compiler/dex/mir_dataflow.cc b/src/compiler/dex/mir_dataflow.cc
index 9f61d73..3b2c1a6 100644
--- a/src/compiler/dex/mir_dataflow.cc
+++ b/src/compiler/dex/mir_dataflow.cc
@@ -16,7 +16,7 @@
 
 #include "compiler_internals.h"
 #include "local_value_numbering.h"
-#include "dataflow_iterator.h"
+#include "dataflow_iterator-inl.h"
 
 namespace art {
 
@@ -70,7 +70,7 @@
   DF_DA | DF_REF_A,
 
   // 0D MOVE_EXCEPTION vAA
-  DF_DA | DF_REF_A,
+  DF_DA | DF_REF_A | DF_NON_NULL_DST,
 
   // 0E RETURN_VOID
   DF_NOP,
@@ -109,13 +109,13 @@
   DF_DA | DF_A_WIDE | DF_SETS_CONST,
 
   // 1A CONST_STRING vAA, string@BBBB
-  DF_DA | DF_REF_A,
+  DF_DA | DF_REF_A | DF_NON_NULL_DST,
 
   // 1B CONST_STRING_JUMBO vAA, string@BBBBBBBB
-  DF_DA | DF_REF_A,
+  DF_DA | DF_REF_A | DF_NON_NULL_DST,
 
   // 1C CONST_CLASS vAA, type@BBBB
-  DF_DA | DF_REF_A,
+  DF_DA | DF_REF_A | DF_NON_NULL_DST,
 
   // 1D MONITOR_ENTER vAA
   DF_UA | DF_NULL_CHK_0 | DF_REF_A,
@@ -933,11 +933,6 @@
   SetNumSSARegs(ssa_reg + 1);
   ssa_base_vregs_->Insert(v_reg);
   ssa_subscripts_->Insert(subscript);
-  std::string ssa_name = GetSSAName(ssa_reg);
-  char* name = static_cast<char*>(arena_->NewMem(ssa_name.length() + 1, false,
-                                                 ArenaAllocator::kAllocDFInfo));
-  strncpy(name, ssa_name.c_str(), ssa_name.length() + 1);
-  ssa_strings_->Insert(name);
   DCHECK_EQ(ssa_base_vregs_->Size(), ssa_subscripts_->Size());
   return ssa_reg;
 }
@@ -1140,8 +1135,6 @@
                                             kGrowableArraySSAtoDalvikMap);
   ssa_subscripts_ = new (arena_) GrowableArray<int>(arena_, num_dalvik_reg + GetDefCount() + 128,
                                             kGrowableArraySSAtoDalvikMap);
-  ssa_strings_ = new (arena_) GrowableArray<char*>(arena_, num_dalvik_reg + GetDefCount() + 128,
-                                           kGrowableArraySSAtoDalvikMap);
   /*
    * Initial number of SSA registers is equal to the number of Dalvik
    * registers.
@@ -1156,11 +1149,6 @@
   for (unsigned int i = 0; i < num_dalvik_reg; i++) {
     ssa_base_vregs_->Insert(i);
     ssa_subscripts_->Insert(0);
-    std::string ssa_name = GetSSAName(i);
-    char* name = static_cast<char*>(arena_->NewMem(ssa_name.length() + 1, true,
-                                                   ArenaAllocator::kAllocDFInfo));
-    strncpy(name, ssa_name.c_str(), ssa_name.length() + 1);
-    ssa_strings_->Insert(name);
   }
 
   /*
@@ -1237,17 +1225,17 @@
       return false;
   }
   DexCompilationUnit m_unit(cu_);
-  // TODO: add a flag so we don't counts the stats for this twice
-  uint32_t dex_method_idx = mir->dalvikInsn.vB;
+  CompilerDriver::MethodReference target_method(cu_->dex_file, mir->dalvikInsn.vB);
   int vtable_idx;
   uintptr_t direct_code;
   uintptr_t direct_method;
   uint32_t current_offset = static_cast<uint32_t>(current_offset_);
   bool fast_path =
-      cu_->compiler_driver->ComputeInvokeInfo(dex_method_idx, current_offset,
-                                              &m_unit, type,
-                                              vtable_idx, direct_code,
-                                              direct_method) &&
+      cu_->compiler_driver->ComputeInvokeInfo(&m_unit, current_offset,
+                                              type, target_method,
+                                              vtable_idx,
+                                              direct_code, direct_method,
+                                              false) &&
                                               !(cu_->enable_debug & (1 << kDebugSlowInvokePath));
   return (((type == kDirect) || (type == kStatic)) &&
           fast_path && ((direct_code == 0) || (direct_method == 0)));
diff --git a/src/compiler/dex/mir_graph.cc b/src/compiler/dex/mir_graph.cc
index 6154eec..11e100d 100644
--- a/src/compiler/dex/mir_graph.cc
+++ b/src/compiler/dex/mir_graph.cc
@@ -77,7 +77,6 @@
       cu_(cu),
       ssa_base_vregs_(NULL),
       ssa_subscripts_(NULL),
-      ssa_strings_(NULL),
       vreg_to_ssa_map_(NULL),
       ssa_last_defs_(NULL),
       is_constant_v_(NULL),
@@ -1037,6 +1036,9 @@
 
 std::string MIRGraph::GetSSAName(int ssa_reg)
 {
+  // TODO: This value is needed for LLVM and debugging. Currently, we compute this and then copy to
+  //       the arena. We should be smarter and just place straight into the arena, or compute the
+  //       value more lazily.
   return StringPrintf("v%d_%d", SRegToVReg(ssa_reg), GetSSASubscript(ssa_reg));
 }
 
diff --git a/src/compiler/dex/mir_graph.h b/src/compiler/dex/mir_graph.h
index 882a508..2b1c21f 100644
--- a/src/compiler/dex/mir_graph.h
+++ b/src/compiler/dex/mir_graph.h
@@ -452,10 +452,6 @@
     return ssa_subscripts_->Get(ssa_reg);
   }
 
-  const char* GetSSAString(int ssa_reg) const {
-    return ssa_strings_->Get(ssa_reg);
-  }
-
   RegLocation GetRawSrc(MIR* mir, int num)
   {
     DCHECK(num < mir->ssa_rep->num_uses);
@@ -628,7 +624,6 @@
    CompilationUnit* const cu_;
    GrowableArray<int>* ssa_base_vregs_;
    GrowableArray<int>* ssa_subscripts_;
-   GrowableArray<char*>* ssa_strings_;
    // Map original Dalvik virtual reg i to the current SSA name.
    int* vreg_to_ssa_map_;            // length == method->registers_size
    int* ssa_last_defs_;              // length == method->registers_size
diff --git a/src/compiler/dex/mir_optimization.cc b/src/compiler/dex/mir_optimization.cc
index 5345501..6b8f3f0 100644
--- a/src/compiler/dex/mir_optimization.cc
+++ b/src/compiler/dex/mir_optimization.cc
@@ -16,7 +16,7 @@
 
 #include "compiler_internals.h"
 #include "local_value_numbering.h"
-#include "dataflow_iterator.h"
+#include "dataflow_iterator-inl.h"
 
 namespace art {
 
@@ -418,6 +418,13 @@
                   static_cast<bool*>(arena_->NewMem(sizeof(bool) * 1, false,
                                                     ArenaAllocator::kAllocDFInfo));
               mir->ssa_rep->fp_def[0] = if_true->ssa_rep->fp_def[0];
+              // Match type of uses to def.
+              mir->ssa_rep->fp_use =
+                  static_cast<bool*>(arena_->NewMem(sizeof(bool) * mir->ssa_rep->num_uses, false,
+                                                    ArenaAllocator::kAllocDFInfo));
+              for (int i = 0; i < mir->ssa_rep->num_uses; i++) {
+                mir->ssa_rep->fp_use[i] = mir->ssa_rep->fp_def[0];
+              }
               /*
                * There is usually a Phi node in the join block for our two cases.  If the
                * Phi node only contains our two cases as input, we will use the result
@@ -634,8 +641,29 @@
       int this_reg = cu_->num_dalvik_registers - cu_->num_ins;
       temp_ssa_register_v_->SetBit(this_reg);
     }
+  } else if (bb->predecessors->Size() == 1) {
+    BasicBlock* pred_bb = bb->predecessors->Get(0);
+    temp_ssa_register_v_->Copy(pred_bb->data_flow_info->ending_null_check_v);
+    if (pred_bb->block_type == kDalvikByteCode) {
+      // Check to see if predecessor had an explicit null-check.
+      MIR* last_insn = pred_bb->last_mir_insn;
+      Instruction::Code last_opcode = last_insn->dalvikInsn.opcode;
+      if (last_opcode == Instruction::IF_EQZ) {
+        if (pred_bb->fall_through == bb) {
+          // The fall-through of a block following a IF_EQZ, set the vA of the IF_EQZ to show that
+          // it can't be null.
+          temp_ssa_register_v_->SetBit(last_insn->ssa_rep->uses[0]);
+        }
+      } else if (last_opcode == Instruction::IF_NEZ) {
+        if (pred_bb->taken == bb) {
+          // The taken block following a IF_NEZ, set the vA of the IF_NEZ to show that it can't be
+          // null.
+          temp_ssa_register_v_->SetBit(last_insn->ssa_rep->uses[0]);
+        }
+      }
+    }
   } else {
-    // Starting state is intesection of all incoming arcs
+    // Starting state is intersection of all incoming arcs
     GrowableArray<BasicBlock*>::Iterator iter(bb->predecessors);
     BasicBlock* pred_bb = iter.Next();
     DCHECK(pred_bb != NULL);
diff --git a/src/compiler/dex/portable/mir_to_gbc.cc b/src/compiler/dex/portable/mir_to_gbc.cc
index 6fccb47..1f9c92a 100644
--- a/src/compiler/dex/portable/mir_to_gbc.cc
+++ b/src/compiler/dex/portable/mir_to_gbc.cc
@@ -28,7 +28,7 @@
 #include <llvm/Support/ToolOutputFile.h>
 
 #include "compiler/dex/compiler_internals.h"
-#include "compiler/dex/dataflow_iterator.h"
+#include "compiler/dex/dataflow_iterator-inl.h"
 #include "compiler/dex/frontend.h"
 #include "mir_to_gbc.h"
 
@@ -1964,7 +1964,7 @@
       ::llvm::Constant* imm_value = mir_graph_->reg_location_[i].wide ?
          irb_->getJLong(0) : irb_->getJInt(0);
       val = EmitConst(imm_value, mir_graph_->reg_location_[i]);
-      val->setName(mir_graph_->GetSSAString(i));
+      val->setName(mir_graph_->GetSSAName(i));
       llvm_values_.Insert(val);
     } else {
       // Recover previously-created argument values
diff --git a/src/compiler/dex/quick/arm/assemble_arm.cc b/src/compiler/dex/quick/arm/assemble_arm.cc
index 23a87dc..36038f7 100644
--- a/src/compiler/dex/quick/arm/assemble_arm.cc
+++ b/src/compiler/dex/quick/arm/assemble_arm.cc
@@ -16,6 +16,7 @@
 
 #include "arm_lir.h"
 #include "codegen_arm.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 
 namespace art {
 
diff --git a/src/compiler/dex/quick/arm/call_arm.cc b/src/compiler/dex/quick/arm/call_arm.cc
index 32d4ed6..77e09b8 100644
--- a/src/compiler/dex/quick/arm/call_arm.cc
+++ b/src/compiler/dex/quick/arm/call_arm.cc
@@ -18,6 +18,7 @@
 
 #include "arm_lir.h"
 #include "codegen_arm.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "oat/runtime/oat_support_entrypoints.h"
 
 namespace art {
diff --git a/src/compiler/dex/quick/arm/codegen_arm.h b/src/compiler/dex/quick/arm/codegen_arm.h
index 9e409e6..60111d1 100644
--- a/src/compiler/dex/quick/arm/codegen_arm.h
+++ b/src/compiler/dex/quick/arm/codegen_arm.h
@@ -23,143 +23,142 @@
 
 class ArmMir2Lir : public Mir2Lir {
   public:
-
     ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
 
     // Required for target - codegen helpers.
-    virtual bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
+    bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
                                     RegLocation rl_dest, int lit);
-    virtual int LoadHelper(int offset);
-    virtual LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
-    virtual LIR* LoadBaseDispWide(int rBase, int displacement, int r_dest_lo, int r_dest_hi,
-                                  int s_reg);
-    virtual LIR* LoadBaseIndexed(int rBase, int r_index, int r_dest, int scale, OpSize size);
-    virtual LIR* LoadBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
-                                     int r_dest, int r_dest_hi, OpSize size, int s_reg);
-    virtual LIR* LoadConstantNoClobber(int r_dest, int value);
-    virtual LIR* LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value);
-    virtual LIR* StoreBaseDisp(int rBase, int displacement, int r_src, OpSize size);
-    virtual LIR* StoreBaseDispWide(int rBase, int displacement, int r_src_lo, int r_src_hi);
-    virtual LIR* StoreBaseIndexed(int rBase, int r_index, int r_src, int scale, OpSize size);
-    virtual LIR* StoreBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
-                                      int r_src, int r_src_hi, OpSize size, int s_reg);
-    virtual void MarkGCCard(int val_reg, int tgt_addr_reg);
+    int LoadHelper(int offset);
+    LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
+    LIR* LoadBaseDispWide(int rBase, int displacement, int r_dest_lo, int r_dest_hi,
+                          int s_reg);
+    LIR* LoadBaseIndexed(int rBase, int r_index, int r_dest, int scale, OpSize size);
+    LIR* LoadBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
+                             int r_dest, int r_dest_hi, OpSize size, int s_reg);
+    LIR* LoadConstantNoClobber(int r_dest, int value);
+    LIR* LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value);
+    LIR* StoreBaseDisp(int rBase, int displacement, int r_src, OpSize size);
+    LIR* StoreBaseDispWide(int rBase, int displacement, int r_src_lo, int r_src_hi);
+    LIR* StoreBaseIndexed(int rBase, int r_index, int r_src, int scale, OpSize size);
+    LIR* StoreBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
+                              int r_src, int r_src_hi, OpSize size, int s_reg);
+    void MarkGCCard(int val_reg, int tgt_addr_reg);
 
     // Required for target - register utilities.
-    virtual bool IsFpReg(int reg);
-    virtual bool SameRegType(int reg1, int reg2);
-    virtual int AllocTypedTemp(bool fp_hint, int reg_class);
-    virtual int AllocTypedTempPair(bool fp_hint, int reg_class);
-    virtual int S2d(int low_reg, int high_reg);
-    virtual int TargetReg(SpecialTargetRegister reg);
-    virtual RegisterInfo* GetRegInfo(int reg);
-    virtual RegLocation GetReturnAlt();
-    virtual RegLocation GetReturnWideAlt();
-    virtual RegLocation LocCReturn();
-    virtual RegLocation LocCReturnDouble();
-    virtual RegLocation LocCReturnFloat();
-    virtual RegLocation LocCReturnWide();
-    virtual uint32_t FpRegMask();
-    virtual uint64_t GetRegMaskCommon(int reg);
-    virtual void AdjustSpillMask();
-    virtual void ClobberCalleeSave();
-    virtual void FlushReg(int reg);
-    virtual void FlushRegWide(int reg1, int reg2);
-    virtual void FreeCallTemps();
-    virtual void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
-    virtual void LockCallTemps();
-    virtual void MarkPreservedSingle(int v_reg, int reg);
-    virtual void CompilerInitializeRegAlloc();
+    bool IsFpReg(int reg);
+    bool SameRegType(int reg1, int reg2);
+    int AllocTypedTemp(bool fp_hint, int reg_class);
+    int AllocTypedTempPair(bool fp_hint, int reg_class);
+    int S2d(int low_reg, int high_reg);
+    int TargetReg(SpecialTargetRegister reg);
+    RegisterInfo* GetRegInfo(int reg);
+    RegLocation GetReturnAlt();
+    RegLocation GetReturnWideAlt();
+    RegLocation LocCReturn();
+    RegLocation LocCReturnDouble();
+    RegLocation LocCReturnFloat();
+    RegLocation LocCReturnWide();
+    uint32_t FpRegMask();
+    uint64_t GetRegMaskCommon(int reg);
+    void AdjustSpillMask();
+    void ClobberCalleeSave();
+    void FlushReg(int reg);
+    void FlushRegWide(int reg1, int reg2);
+    void FreeCallTemps();
+    void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
+    void LockCallTemps();
+    void MarkPreservedSingle(int v_reg, int reg);
+    void CompilerInitializeRegAlloc();
 
     // Required for target - miscellaneous.
-    virtual AssemblerStatus AssembleInstructions(uintptr_t start_addr);
-    virtual void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix);
-    virtual void SetupTargetResourceMasks(LIR* lir);
-    virtual const char* GetTargetInstFmt(int opcode);
-    virtual const char* GetTargetInstName(int opcode);
-    virtual std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr);
-    virtual uint64_t GetPCUseDefEncoding();
-    virtual uint64_t GetTargetInstFlags(int opcode);
-    virtual int GetInsnSize(LIR* lir);
-    virtual bool IsUnconditionalBranch(LIR* lir);
+    AssemblerStatus AssembleInstructions(uintptr_t start_addr);
+    void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix);
+    void SetupTargetResourceMasks(LIR* lir);
+    const char* GetTargetInstFmt(int opcode);
+    const char* GetTargetInstName(int opcode);
+    std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr);
+    uint64_t GetPCUseDefEncoding();
+    uint64_t GetTargetInstFlags(int opcode);
+    int GetInsnSize(LIR* lir);
+    bool IsUnconditionalBranch(LIR* lir);
 
     // Required for target - Dalvik-level generators.
-    virtual void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
-                                   RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenArrayObjPut(int opt_flags, RegLocation rl_array, RegLocation rl_index,
-                                RegLocation rl_src, int scale);
-    virtual void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
-                             RegLocation rl_index, RegLocation rl_dest, int scale);
-    virtual void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
-                             RegLocation rl_index, RegLocation rl_src, int scale);
-    virtual void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
-                                   RegLocation rl_src1, RegLocation rl_shift);
-    virtual void GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenAndLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
-                                  RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
-                                 RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
-                          RegLocation rl_src2);
-    virtual void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
-    virtual bool GenInlinedCas32(CallInfo* info, bool need_write_barrier);
-    virtual bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
-    virtual bool GenInlinedSqrt(CallInfo* info);
-    virtual void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
-    virtual void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenXorLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base, int offset,
+    void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
+                           RegLocation rl_src1, RegLocation rl_src2);
+    void GenArrayObjPut(int opt_flags, RegLocation rl_array, RegLocation rl_index,
+                        RegLocation rl_src, int scale);
+    void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
+                     RegLocation rl_index, RegLocation rl_dest, int scale);
+    void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
+                     RegLocation rl_index, RegLocation rl_src, int scale);
+    void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
+                           RegLocation rl_src1, RegLocation rl_shift);
+    void GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenAndLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
+                          RegLocation rl_src1, RegLocation rl_src2);
+    void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
+                         RegLocation rl_src1, RegLocation rl_src2);
+    void GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
+                  RegLocation rl_src2);
+    void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
+    bool GenInlinedCas32(CallInfo* info, bool need_write_barrier);
+    bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
+    bool GenInlinedSqrt(CallInfo* info);
+    void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
+    void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenXorLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base, int offset,
                                 ThrowKind kind);
-    virtual RegLocation GenDivRem(RegLocation rl_dest, int reg_lo, int reg_hi, bool is_div);
-    virtual RegLocation GenDivRemLit(RegLocation rl_dest, int reg_lo, int lit, bool is_div);
-    virtual void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenDivZeroCheck(int reg_lo, int reg_hi);
-    virtual void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
-    virtual void GenExitSequence();
-    virtual void GenFillArrayData(uint32_t table_offset, RegLocation rl_src);
-    virtual void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
-    virtual void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
-    virtual void GenSelect(BasicBlock* bb, MIR* mir);
-    virtual void GenMemBarrier(MemBarrierKind barrier_kind);
-    virtual void GenMonitorEnter(int opt_flags, RegLocation rl_src);
-    virtual void GenMonitorExit(int opt_flags, RegLocation rl_src);
-    virtual void GenMoveException(RegLocation rl_dest);
-    virtual void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit,
+    RegLocation GenDivRem(RegLocation rl_dest, int reg_lo, int reg_hi, bool is_div);
+    RegLocation GenDivRemLit(RegLocation rl_dest, int reg_lo, int lit, bool is_div);
+    void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenDivZeroCheck(int reg_lo, int reg_hi);
+    void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
+    void GenExitSequence();
+    void GenFillArrayData(uint32_t table_offset, RegLocation rl_src);
+    void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
+    void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
+    void GenSelect(BasicBlock* bb, MIR* mir);
+    void GenMemBarrier(MemBarrierKind barrier_kind);
+    void GenMonitorEnter(int opt_flags, RegLocation rl_src);
+    void GenMonitorExit(int opt_flags, RegLocation rl_src);
+    void GenMoveException(RegLocation rl_dest);
+    void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit,
                                                int first_bit, int second_bit);
-    virtual void GenNegDouble(RegLocation rl_dest, RegLocation rl_src);
-    virtual void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
-    virtual void GenPackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
-    virtual void GenSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
-    virtual void GenSpecialCase(BasicBlock* bb, MIR* mir, SpecialCaseHandler special_case);
+    void GenNegDouble(RegLocation rl_dest, RegLocation rl_src);
+    void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
+    void GenPackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
+    void GenSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
+    void GenSpecialCase(BasicBlock* bb, MIR* mir, SpecialCaseHandler special_case);
 
     // Required for target - single operation generators.
-    virtual LIR* OpUnconditionalBranch(LIR* target);
-    virtual LIR* OpCmpBranch(ConditionCode cond, int src1, int src2, LIR* target);
-    virtual LIR* OpCmpImmBranch(ConditionCode cond, int reg, int check_value, LIR* target);
-    virtual LIR* OpCondBranch(ConditionCode cc, LIR* target);
-    virtual LIR* OpDecAndBranch(ConditionCode c_code, int reg, LIR* target);
-    virtual LIR* OpFpRegCopy(int r_dest, int r_src);
-    virtual LIR* OpIT(ConditionCode cond, const char* guide);
-    virtual LIR* OpMem(OpKind op, int rBase, int disp);
-    virtual LIR* OpPcRelLoad(int reg, LIR* target);
-    virtual LIR* OpReg(OpKind op, int r_dest_src);
-    virtual LIR* OpRegCopy(int r_dest, int r_src);
-    virtual LIR* OpRegCopyNoInsert(int r_dest, int r_src);
-    virtual LIR* OpRegImm(OpKind op, int r_dest_src1, int value);
-    virtual LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset);
-    virtual LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
-    virtual LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
-    virtual LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
-    virtual LIR* OpTestSuspend(LIR* target);
-    virtual LIR* OpThreadMem(OpKind op, int thread_offset);
-    virtual LIR* OpVldm(int rBase, int count);
-    virtual LIR* OpVstm(int rBase, int count);
-    virtual void OpLea(int rBase, int reg1, int reg2, int scale, int offset);
-    virtual void OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, int src_hi);
-    virtual void OpTlsCmp(int offset, int val);
+    LIR* OpUnconditionalBranch(LIR* target);
+    LIR* OpCmpBranch(ConditionCode cond, int src1, int src2, LIR* target);
+    LIR* OpCmpImmBranch(ConditionCode cond, int reg, int check_value, LIR* target);
+    LIR* OpCondBranch(ConditionCode cc, LIR* target);
+    LIR* OpDecAndBranch(ConditionCode c_code, int reg, LIR* target);
+    LIR* OpFpRegCopy(int r_dest, int r_src);
+    LIR* OpIT(ConditionCode cond, const char* guide);
+    LIR* OpMem(OpKind op, int rBase, int disp);
+    LIR* OpPcRelLoad(int reg, LIR* target);
+    LIR* OpReg(OpKind op, int r_dest_src);
+    LIR* OpRegCopy(int r_dest, int r_src);
+    LIR* OpRegCopyNoInsert(int r_dest, int r_src);
+    LIR* OpRegImm(OpKind op, int r_dest_src1, int value);
+    LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset);
+    LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
+    LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
+    LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
+    LIR* OpTestSuspend(LIR* target);
+    LIR* OpThreadMem(OpKind op, int thread_offset);
+    LIR* OpVldm(int rBase, int count);
+    LIR* OpVstm(int rBase, int count);
+    void OpLea(int rBase, int reg1, int reg2, int scale, int offset);
+    void OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, int src_hi);
+    void OpTlsCmp(int offset, int val);
 
     RegLocation ArgLoc(RegLocation loc);
     LIR* LoadBaseDispBody(int rBase, int displacement, int r_dest, int r_dest_hi, OpSize size,
diff --git a/src/compiler/dex/quick/arm/fp_arm.cc b/src/compiler/dex/quick/arm/fp_arm.cc
index 4bf8738..cd71c07 100644
--- a/src/compiler/dex/quick/arm/fp_arm.cc
+++ b/src/compiler/dex/quick/arm/fp_arm.cc
@@ -16,6 +16,7 @@
 
 #include "arm_lir.h"
 #include "codegen_arm.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 
 namespace art {
 
diff --git a/src/compiler/dex/quick/arm/int_arm.cc b/src/compiler/dex/quick/arm/int_arm.cc
index 586a3a4..110e9f4 100644
--- a/src/compiler/dex/quick/arm/int_arm.cc
+++ b/src/compiler/dex/quick/arm/int_arm.cc
@@ -18,6 +18,7 @@
 
 #include "arm_lir.h"
 #include "codegen_arm.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "mirror/array.h"
 #include "oat/runtime/oat_support_entrypoints.h"
 
diff --git a/src/compiler/dex/quick/arm/target_arm.cc b/src/compiler/dex/quick/arm/target_arm.cc
index 0a05a3a..ee127a8 100644
--- a/src/compiler/dex/quick/arm/target_arm.cc
+++ b/src/compiler/dex/quick/arm/target_arm.cc
@@ -19,6 +19,7 @@
 #include "arm_lir.h"
 #include "codegen_arm.h"
 #include "compiler/dex/compiler_internals.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 
 namespace art {
 
diff --git a/src/compiler/dex/quick/arm/utility_arm.cc b/src/compiler/dex/quick/arm/utility_arm.cc
index c689f72..ef0cc72 100644
--- a/src/compiler/dex/quick/arm/utility_arm.cc
+++ b/src/compiler/dex/quick/arm/utility_arm.cc
@@ -16,7 +16,7 @@
 
 #include "arm_lir.h"
 #include "codegen_arm.h"
-#include "compiler/dex/quick/mir_to_lir.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 
 namespace art {
 
diff --git a/src/compiler/dex/quick/codegen_util.cc b/src/compiler/dex/quick/codegen_util.cc
index 517d1b5..ac2828c 100644
--- a/src/compiler/dex/quick/codegen_util.cc
+++ b/src/compiler/dex/quick/codegen_util.cc
@@ -17,6 +17,7 @@
 #include "compiler/dex/compiler_internals.h"
 #include "dex_file-inl.h"
 #include "gc_map.h"
+#include "mir_to_lir-inl.h"
 #include "verifier/dex_gc_map.h"
 #include "verifier/method_verifier.h"
 
@@ -112,81 +113,6 @@
 }
 
 /*
- * Mark the corresponding bit(s).
- */
-void Mir2Lir::SetupRegMask(uint64_t* mask, int reg)
-{
-  *mask |= GetRegMaskCommon(reg);
-}
-
-/*
- * Set up the proper fields in the resource mask
- */
-void Mir2Lir::SetupResourceMasks(LIR* lir)
-{
-  int opcode = lir->opcode;
-
-  if (opcode <= 0) {
-    lir->use_mask = lir->def_mask = 0;
-    return;
-  }
-
-  uint64_t flags = GetTargetInstFlags(opcode);
-
-  if (flags & NEEDS_FIXUP) {
-    lir->flags.pcRelFixup = true;
-  }
-
-  /* Get the starting size of the instruction's template */
-  lir->flags.size = GetInsnSize(lir);
-
-  /* Set up the mask for resources that are updated */
-  if (flags & (IS_LOAD | IS_STORE)) {
-    /* Default to heap - will catch specialized classes later */
-    SetMemRefType(lir, flags & IS_LOAD, kHeapRef);
-  }
-
-  /*
-   * Conservatively assume the branch here will call out a function that in
-   * turn will trash everything.
-   */
-  if (flags & IS_BRANCH) {
-    lir->def_mask = lir->use_mask = ENCODE_ALL;
-    return;
-  }
-
-  if (flags & REG_DEF0) {
-    SetupRegMask(&lir->def_mask, lir->operands[0]);
-  }
-
-  if (flags & REG_DEF1) {
-    SetupRegMask(&lir->def_mask, lir->operands[1]);
-  }
-
-
-  if (flags & SETS_CCODES) {
-    lir->def_mask |= ENCODE_CCODE;
-  }
-
-  if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
-    int i;
-
-    for (i = 0; i < 4; i++) {
-      if (flags & (1 << (kRegUse0 + i))) {
-        SetupRegMask(&lir->use_mask, lir->operands[i]);
-      }
-    }
-  }
-
-  if (flags & USES_CCODES) {
-    lir->use_mask |= ENCODE_CCODE;
-  }
-
-  // Handle target-specific actions
-  SetupTargetResourceMasks(lir);
-}
-
-/*
  * Debugging macros
  */
 #define DUMP_RESOURCE_MASK(X)
@@ -361,99 +287,6 @@
   DumpMappingTable("Dex2PC_MappingTable", descriptor, name, signature, dex2pc_mapping_table_);
 }
 
-
-LIR* Mir2Lir::RawLIR(int dalvik_offset, int opcode, int op0,
-                     int op1, int op2, int op3, int op4, LIR* target)
-{
-  LIR* insn = static_cast<LIR*>(arena_->NewMem(sizeof(LIR), true, ArenaAllocator::kAllocLIR));
-  insn->dalvik_offset = dalvik_offset;
-  insn->opcode = opcode;
-  insn->operands[0] = op0;
-  insn->operands[1] = op1;
-  insn->operands[2] = op2;
-  insn->operands[3] = op3;
-  insn->operands[4] = op4;
-  insn->target = target;
-  SetupResourceMasks(insn);
-  if ((opcode == kPseudoTargetLabel) || (opcode == kPseudoSafepointPC) ||
-      (opcode == kPseudoExportedPC)) {
-    // Always make labels scheduling barriers
-    insn->use_mask = insn->def_mask = ENCODE_ALL;
-  }
-  return insn;
-}
-
-/*
- * The following are building blocks to construct low-level IRs with 0 - 4
- * operands.
- */
-LIR* Mir2Lir::NewLIR0(int opcode)
-{
-  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & NO_OPERAND))
-      << GetTargetInstName(opcode) << " " << opcode << " "
-      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
-      << current_dalvik_offset_;
-  LIR* insn = RawLIR(current_dalvik_offset_, opcode);
-  AppendLIR(insn);
-  return insn;
-}
-
-LIR* Mir2Lir::NewLIR1(int opcode, int dest)
-{
-  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_UNARY_OP))
-      << GetTargetInstName(opcode) << " " << opcode << " "
-      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
-      << current_dalvik_offset_;
-  LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest);
-  AppendLIR(insn);
-  return insn;
-}
-
-LIR* Mir2Lir::NewLIR2(int opcode, int dest, int src1)
-{
-  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_BINARY_OP))
-      << GetTargetInstName(opcode) << " " << opcode << " "
-      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
-      << current_dalvik_offset_;
-  LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1);
-  AppendLIR(insn);
-  return insn;
-}
-
-LIR* Mir2Lir::NewLIR3(int opcode, int dest, int src1, int src2)
-{
-  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_TERTIARY_OP))
-      << GetTargetInstName(opcode) << " " << opcode << " "
-      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
-      << current_dalvik_offset_;
-  LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1, src2);
-  AppendLIR(insn);
-  return insn;
-}
-
-LIR* Mir2Lir::NewLIR4(int opcode, int dest, int src1, int src2, int info)
-{
-  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_QUAD_OP))
-      << GetTargetInstName(opcode) << " " << opcode << " "
-      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
-      << current_dalvik_offset_;
-  LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1, src2, info);
-  AppendLIR(insn);
-  return insn;
-}
-
-LIR* Mir2Lir::NewLIR5(int opcode, int dest, int src1, int src2, int info1,
-                      int info2)
-{
-  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_QUIN_OP))
-      << GetTargetInstName(opcode) << " " << opcode << " "
-      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
-      << current_dalvik_offset_;
-  LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1, src2, info1, info2);
-  AppendLIR(insn);
-  return insn;
-}
-
 /*
  * Search the existing constants in the literal pool for an exact or close match
  * within specified delta (greater or equal to 0).
diff --git a/src/compiler/dex/quick/gen_common.cc b/src/compiler/dex/quick/gen_common.cc
index 15aa904..7aa71cf 100644
--- a/src/compiler/dex/quick/gen_common.cc
+++ b/src/compiler/dex/quick/gen_common.cc
@@ -16,8 +16,10 @@
 
 #include "compiler/dex/compiler_ir.h"
 #include "compiler/dex/compiler_internals.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "mirror/array.h"
 #include "oat/runtime/oat_support_entrypoints.h"
+#include "verifier/method_verifier.h"
 
 namespace art {
 
@@ -881,23 +883,81 @@
   CallRuntimeHelperRegLocation(ENTRYPOINT_OFFSET(pDeliverException), rl_src, true);
 }
 
-void Mir2Lir::GenInstanceof(uint32_t type_idx, RegLocation rl_dest,
-                            RegLocation rl_src)
-{
+// For final classes there are no sub-classes to check and so we can answer the instance-of
+// question with simple comparisons.
+void Mir2Lir::GenInstanceofFinal(bool use_declaring_class, uint32_t type_idx, RegLocation rl_dest,
+                                 RegLocation rl_src) {
+  RegLocation object = LoadValue(rl_src, kCoreReg);
+  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+  int result_reg = rl_result.low_reg;
+  if (result_reg == object.low_reg) {
+    result_reg = AllocTypedTemp(false, kCoreReg);
+  }
+  LoadConstant(result_reg, 0);     // assume false
+  LIR* null_branchover = OpCmpImmBranch(kCondEq, object.low_reg, 0, NULL);
+
+  int check_class = AllocTypedTemp(false, kCoreReg);
+  int object_class = AllocTypedTemp(false, kCoreReg);
+
+  LoadCurrMethodDirect(check_class);
+  if (use_declaring_class) {
+    LoadWordDisp(check_class, mirror::AbstractMethod::DeclaringClassOffset().Int32Value(),
+                 check_class);
+    LoadWordDisp(object.low_reg,  mirror::Object::ClassOffset().Int32Value(), object_class);
+  } else {
+    LoadWordDisp(check_class, mirror::AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(),
+                 check_class);
+    LoadWordDisp(object.low_reg,  mirror::Object::ClassOffset().Int32Value(), object_class);
+    int32_t offset_of_type =
+      mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() +
+      (sizeof(mirror::Class*) * type_idx);
+    LoadWordDisp(check_class, offset_of_type, check_class);
+  }
+
+  LIR* ne_branchover = NULL;
+  if (cu_->instruction_set == kThumb2) {
+    OpRegReg(kOpCmp, check_class, object_class);  // Same?
+    OpIT(kCondEq, "");   // if-convert the test
+    LoadConstant(result_reg, 1);     // .eq case - load true
+  } else {
+    ne_branchover = OpCmpBranch(kCondNe, check_class, object_class, NULL);
+    LoadConstant(result_reg, 1);     // eq case - load true
+  }
+  LIR* target = NewLIR0(kPseudoTargetLabel);
+  null_branchover->target = target;
+  if (ne_branchover != NULL) {
+    ne_branchover->target = target;
+  }
+  FreeTemp(object_class);
+  FreeTemp(check_class);
+  if (IsTemp(result_reg)) {
+    OpRegCopy(rl_result.low_reg, result_reg);
+    FreeTemp(result_reg);
+  }
+  StoreValue(rl_dest, rl_result);
+}
+
+void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_known_final,
+                                         bool type_known_abstract, bool use_declaring_class,
+                                         bool can_assume_type_is_in_dex_cache,
+                                         uint32_t type_idx, RegLocation rl_dest,
+                                         RegLocation rl_src) {
   FlushAllRegs();
   // May generate a call - use explicit registers
   LockCallTemps();
   LoadCurrMethodDirect(TargetReg(kArg1));  // kArg1 <= current Method*
   int class_reg = TargetReg(kArg2);  // kArg2 will hold the Class*
-  if (!cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx,
-                                                   *cu_->dex_file,
-                                                   type_idx)) {
+  if (needs_access_check) {
     // Check we have access to type_idx and if not throw IllegalAccessError,
     // returns Class* in kArg0
     CallRuntimeHelperImm(ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
                          type_idx, true);
     OpRegCopy(class_reg, TargetReg(kRet0));  // Align usage with fast path
     LoadValueDirectFixed(rl_src, TargetReg(kArg0));  // kArg0 <= ref
+  } else if (use_declaring_class) {
+    LoadValueDirectFixed(rl_src, TargetReg(kArg0));  // kArg0 <= ref
+    LoadWordDisp(TargetReg(kArg1),
+                 mirror::AbstractMethod::DeclaringClassOffset().Int32Value(), class_reg);
   } else {
     // Load dex cache entry into class_reg (kArg2)
     LoadValueDirectFixed(rl_src, TargetReg(kArg0));  // kArg0 <= ref
@@ -907,8 +967,7 @@
         mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + (sizeof(mirror::Class*)
         * type_idx);
     LoadWordDisp(class_reg, offset_of_type, class_reg);
-    if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(
-        *cu_->dex_file, type_idx)) {
+    if (!can_assume_type_is_in_dex_cache) {
       // Need to test presence of type in dex cache at runtime
       LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL);
       // Not resolved
@@ -924,65 +983,120 @@
   /* kArg0 is ref, kArg2 is class. If ref==null, use directly as bool result */
   RegLocation rl_result = GetReturn(false);
   if (cu_->instruction_set == kMips) {
-    LoadConstant(rl_result.low_reg, 0);  // store false result for if branch is taken
+    // On MIPS rArg0 != rl_result, place false in result if branch is taken.
+    LoadConstant(rl_result.low_reg, 0);
   }
   LIR* branch1 = OpCmpImmBranch(kCondEq, TargetReg(kArg0), 0, NULL);
+
   /* load object->klass_ */
   DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0);
   LoadWordDisp(TargetReg(kArg0),  mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1));
   /* kArg0 is ref, kArg1 is ref->klass_, kArg2 is class */
-  LIR* call_inst;
   LIR* branchover = NULL;
-  if (cu_->instruction_set == kThumb2) {
-    /* Uses conditional nullification */
-    int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
-    OpRegReg(kOpCmp, TargetReg(kArg1), TargetReg(kArg2));  // Same?
-    OpIT(kCondEq, "EE");   // if-convert the test
-    LoadConstant(TargetReg(kArg0), 1);     // .eq case - load true
-    OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));    // .ne case - arg0 <= class
-    call_inst = OpReg(kOpBlx, r_tgt);    // .ne case: helper(class, ref->class)
-    FreeTemp(r_tgt);
+  if (type_known_final) {
+    // rl_result == ref == null == 0.
+    if (cu_->instruction_set == kThumb2) {
+      OpRegReg(kOpCmp, TargetReg(kArg1), TargetReg(kArg2));  // Same?
+      OpIT(kCondEq, "E");   // if-convert the test
+      LoadConstant(rl_result.low_reg, 1);     // .eq case - load true
+      LoadConstant(rl_result.low_reg, 0);     // .ne case - load false
+    } else {
+      LoadConstant(rl_result.low_reg, 0);     // ne case - load false
+      branchover = OpCmpBranch(kCondNe, TargetReg(kArg1), TargetReg(kArg2), NULL);
+      LoadConstant(rl_result.low_reg, 1);     // eq case - load true
+    }
   } else {
-    /* Uses branchovers */
-    LoadConstant(rl_result.low_reg, 1);     // assume true
-    branchover = OpCmpBranch(kCondEq, TargetReg(kArg1), TargetReg(kArg2), NULL);
-    if (cu_->instruction_set != kX86) {
+    if (cu_->instruction_set == kThumb2) {
       int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
+      if (!type_known_abstract) {
+      /* Uses conditional nullification */
+        OpRegReg(kOpCmp, TargetReg(kArg1), TargetReg(kArg2));  // Same?
+        OpIT(kCondEq, "EE");   // if-convert the test
+        LoadConstant(TargetReg(kArg0), 1);     // .eq case - load true
+      }
       OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));    // .ne case - arg0 <= class
-      call_inst = OpReg(kOpBlx, r_tgt);    // .ne case: helper(class, ref->class)
+      OpReg(kOpBlx, r_tgt);    // .ne case: helper(class, ref->class)
       FreeTemp(r_tgt);
     } else {
-      OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));
-      call_inst = OpThreadMem(kOpBlx, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
+      if (!type_known_abstract) {
+        /* Uses branchovers */
+        LoadConstant(rl_result.low_reg, 1);     // assume true
+        branchover = OpCmpBranch(kCondEq, TargetReg(kArg1), TargetReg(kArg2), NULL);
+      }
+      if (cu_->instruction_set != kX86) {
+        int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
+        OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));    // .ne case - arg0 <= class
+        OpReg(kOpBlx, r_tgt);    // .ne case: helper(class, ref->class)
+        FreeTemp(r_tgt);
+      } else {
+        OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));
+        OpThreadMem(kOpBlx, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
+      }
     }
   }
-  MarkSafepointPC(call_inst);
+  // TODO: only clobber when type isn't final?
   ClobberCalleeSave();
   /* branch targets here */
   LIR* target = NewLIR0(kPseudoTargetLabel);
   StoreValue(rl_dest, rl_result);
   branch1->target = target;
-  if (cu_->instruction_set != kThumb2) {
+  if (branchover != NULL) {
     branchover->target = target;
   }
 }
 
-void Mir2Lir::GenCheckCast(uint32_t type_idx, RegLocation rl_src)
+void Mir2Lir::GenInstanceof(uint32_t type_idx, RegLocation rl_dest, RegLocation rl_src) {
+  bool type_known_final, type_known_abstract, use_declaring_class;
+  bool needs_access_check = !cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx,
+                                                                              *cu_->dex_file,
+                                                                              type_idx,
+                                                                              &type_known_final,
+                                                                              &type_known_abstract,
+                                                                              &use_declaring_class);
+  bool can_assume_type_is_in_dex_cache = !needs_access_check &&
+      cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file, type_idx);
+
+  if ((use_declaring_class || can_assume_type_is_in_dex_cache) && type_known_final) {
+    GenInstanceofFinal(use_declaring_class, type_idx, rl_dest, rl_src);
+  } else {
+    GenInstanceofCallingHelper(needs_access_check, type_known_final, type_known_abstract,
+                               use_declaring_class, can_assume_type_is_in_dex_cache,
+                               type_idx, rl_dest, rl_src);
+  }
+}
+
+void Mir2Lir::GenCheckCast(uint32_t insn_idx, uint32_t type_idx, RegLocation rl_src)
 {
+  bool type_known_final, type_known_abstract, use_declaring_class;
+  bool needs_access_check = !cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx,
+                                                                              *cu_->dex_file,
+                                                                              type_idx,
+                                                                              &type_known_final,
+                                                                              &type_known_abstract,
+                                                                              &use_declaring_class);
+  // Note: currently type_known_final is unused, as optimizing will only improve the performance
+  // of the exception throw path.
+  DexCompilationUnit* cu = mir_graph_->GetCurrentDexCompilationUnit();
+  const CompilerDriver::MethodReference mr(cu->GetDexFile(), cu->GetDexMethodIndex());
+  if (!needs_access_check && cu_->compiler_driver->IsSafeCast(mr, insn_idx)) {
+    // Verifier type analysis proved this check cast would never cause an exception.
+    return;
+  }
   FlushAllRegs();
   // May generate a call - use explicit registers
   LockCallTemps();
   LoadCurrMethodDirect(TargetReg(kArg1));  // kArg1 <= current Method*
   int class_reg = TargetReg(kArg2);  // kArg2 will hold the Class*
-  if (!cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx,
-                                                   *cu_->dex_file,
-                                                   type_idx)) {
+  if (needs_access_check) {
     // Check we have access to type_idx and if not throw IllegalAccessError,
     // returns Class* in kRet0
     // InitializeTypeAndVerifyAccess(idx, method)
     CallRuntimeHelperImmReg(ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
                             type_idx, TargetReg(kArg1), true);
     OpRegCopy(class_reg, TargetReg(kRet0));  // Align usage with fast path
+  } else if (use_declaring_class) {
+    LoadWordDisp(TargetReg(kArg1),
+                 mirror::AbstractMethod::DeclaringClassOffset().Int32Value(), class_reg);
   } else {
     // Load dex cache entry into class_reg (kArg2)
     LoadWordDisp(TargetReg(kArg1),
@@ -991,8 +1105,7 @@
         mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() +
         (sizeof(mirror::Class*) * type_idx);
     LoadWordDisp(class_reg, offset_of_type, class_reg);
-    if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(
-        *cu_->dex_file, type_idx)) {
+    if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file, type_idx)) {
       // Need to test presence of type in dex cache at runtime
       LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL);
       // Not resolved
@@ -1014,25 +1127,18 @@
   DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0);
   LoadWordDisp(TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1));
   /* kArg1 now contains object->klass_ */
-  LIR* branch2;
-  if (cu_->instruction_set == kThumb2) {
-    int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pCheckCastFromCode));
-    OpRegReg(kOpCmp, TargetReg(kArg1), class_reg);
-    branch2 = OpCondBranch(kCondEq, NULL); /* If eq, trivial yes */
-    OpRegCopy(TargetReg(kArg0), TargetReg(kArg1));
-    OpRegCopy(TargetReg(kArg1), TargetReg(kArg2));
-    ClobberCalleeSave();
-    LIR* call_inst = OpReg(kOpBlx, r_tgt);
-    MarkSafepointPC(call_inst);
-    FreeTemp(r_tgt);
-  } else {
+  LIR* branch2 = NULL;
+  if (!type_known_abstract) {
     branch2 = OpCmpBranch(kCondEq, TargetReg(kArg1), class_reg, NULL);
-    CallRuntimeHelperRegReg(ENTRYPOINT_OFFSET(pCheckCastFromCode), TargetReg(kArg1), TargetReg(kArg2), true);
   }
+  CallRuntimeHelperRegReg(ENTRYPOINT_OFFSET(pCheckCastFromCode), TargetReg(kArg1), TargetReg(kArg2),
+                          true);
   /* branch target here */
   LIR* target = NewLIR0(kPseudoTargetLabel);
   branch1->target = target;
-  branch2->target = target;
+  if (branch2 != NULL) {
+    branch2->target = target;
+  }
 }
 
 void Mir2Lir::GenLong3Addr(OpKind first_op, OpKind second_op, RegLocation rl_dest,
diff --git a/src/compiler/dex/quick/gen_invoke.cc b/src/compiler/dex/quick/gen_invoke.cc
index afcd9ef..4b12bb4 100644
--- a/src/compiler/dex/quick/gen_invoke.cc
+++ b/src/compiler/dex/quick/gen_invoke.cc
@@ -15,9 +15,11 @@
  */
 
 #include "compiler/dex/compiler_ir.h"
+#include "dex_file-inl.h"
 #include "invoke_type.h"
 #include "mirror/array.h"
 #include "mirror/string.h"
+#include "mir_to_lir-inl.h"
 #include "oat/runtime/oat_support_entrypoints.h"
 #include "x86/codegen_x86.h"
 
@@ -311,7 +313,8 @@
  * emit the next instruction in static & direct invoke sequences.
  */
 static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
-                          int state, uint32_t dex_idx, uint32_t unused,
+                          int state, const CompilerDriver::MethodReference& target_method,
+                          uint32_t unused,
                           uintptr_t direct_code, uintptr_t direct_method,
                           InvokeType type)
 {
@@ -327,9 +330,11 @@
       if (direct_code != static_cast<unsigned int>(-1)) {
         cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
       } else {
-        LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_, dex_idx, 0);
+        CHECK_EQ(cu->dex_file, target_method.dex_file);
+        LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_,
+                                               target_method.dex_method_index, 0);
         if (data_target == NULL) {
-          data_target = cg->AddWordData(&cg->code_literal_list_, dex_idx);
+          data_target = cg->AddWordData(&cg->code_literal_list_, target_method.dex_method_index);
           data_target->operands[1] = type;
         }
         LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
@@ -339,9 +344,11 @@
       if (direct_method != static_cast<unsigned int>(-1)) {
         cg->LoadConstant(cg->TargetReg(kArg0), direct_method);
       } else {
-        LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_, dex_idx, 0);
+        CHECK_EQ(cu->dex_file, target_method.dex_file);
+        LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_,
+                                               target_method.dex_method_index, 0);
         if (data_target == NULL) {
-          data_target = cg->AddWordData(&cg->method_literal_list_, dex_idx);
+          data_target = cg->AddWordData(&cg->method_literal_list_, target_method.dex_method_index);
           data_target->operands[1] = type;
         }
         LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target);
@@ -366,9 +373,11 @@
         if (direct_code != static_cast<unsigned int>(-1)) {
           cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
         } else {
-          LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_, dex_idx, 0);
+          CHECK_EQ(cu->dex_file, target_method.dex_file);
+          LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_,
+                                                 target_method.dex_method_index, 0);
           if (data_target == NULL) {
-            data_target = cg->AddWordData(&cg->code_literal_list_, dex_idx);
+            data_target = cg->AddWordData(&cg->code_literal_list_, target_method.dex_method_index);
             data_target->operands[1] = type;
           }
           LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
@@ -378,8 +387,10 @@
       }
       break;
     case 2:  // Grab target method*
+      CHECK_EQ(cu->dex_file, target_method.dex_file);
       cg->LoadWordDisp(cg->TargetReg(kArg0),
-                       mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + dex_idx * 4,
+                       mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
+                           (target_method.dex_method_index * 4),
                        cg-> TargetReg(kArg0));
       break;
     case 3:  // Grab the code from the method*
@@ -407,8 +418,9 @@
  * kArg1 here rather than the standard LoadArgRegs.
  */
 static int NextVCallInsn(CompilationUnit* cu, CallInfo* info,
-                         int state, uint32_t dex_idx, uint32_t method_idx,
-                         uintptr_t unused, uintptr_t unused2, InvokeType unused3)
+                         int state, const CompilerDriver::MethodReference& target_method,
+                         uint32_t method_idx, uintptr_t unused, uintptr_t unused2,
+                         InvokeType unused3)
 {
   Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
   /*
@@ -455,7 +467,8 @@
  * which will locate the target and continue on via a tail call.
  */
 static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state,
-                                 uint32_t dex_idx, uint32_t unused, uintptr_t unused2,
+                                 const CompilerDriver::MethodReference& target_method,
+                                 uint32_t unused, uintptr_t unused2,
                                  uintptr_t direct_method, InvokeType unused4)
 {
   Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
@@ -476,9 +489,12 @@
         if (direct_method != static_cast<unsigned int>(-1)) {
           cg->LoadConstant(cg->TargetReg(kArg0), direct_method);
         } else {
-          LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_, dex_idx, 0);
+          CHECK_EQ(cu->dex_file, target_method.dex_file);
+          LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_,
+                                                 target_method.dex_method_index, 0);
           if (data_target == NULL) {
-            data_target = cg->AddWordData(&cg->method_literal_list_, dex_idx);
+            data_target = cg->AddWordData(&cg->method_literal_list_,
+                                          target_method.dex_method_index);
             data_target->operands[1] = kInterface;
           }
           LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target);
@@ -505,8 +521,10 @@
                        cg->TargetReg(kArg0));
       break;
     case 2:  // Grab target method* [set/use kArg0]
+      CHECK_EQ(cu->dex_file, target_method.dex_file);
       cg->LoadWordDisp(cg->TargetReg(kArg0),
-                       mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + dex_idx * 4,
+                       mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
+                           (target_method.dex_method_index * 4),
                        cg->TargetReg(kArg0));
       break;
     default:
@@ -517,7 +535,8 @@
 }
 
 static int NextInvokeInsnSP(CompilationUnit* cu, CallInfo* info, int trampoline,
-                            int state, uint32_t dex_idx, uint32_t method_idx)
+                            int state, const CompilerDriver::MethodReference& target_method,
+                            uint32_t method_idx)
 {
   Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
   /*
@@ -530,58 +549,66 @@
       cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline, cg->TargetReg(kInvokeTgt));
     }
     // Load kArg0 with method index
-    cg->LoadConstant(cg->TargetReg(kArg0), dex_idx);
+    CHECK_EQ(cu->dex_file, target_method.dex_file);
+    cg->LoadConstant(cg->TargetReg(kArg0), target_method.dex_method_index);
     return 1;
   }
   return -1;
 }
 
 static int NextStaticCallInsnSP(CompilationUnit* cu, CallInfo* info,
-                                int state, uint32_t dex_idx, uint32_t method_idx,
+                                int state,
+                                const CompilerDriver::MethodReference& target_method,
+                                uint32_t method_idx,
                                 uintptr_t unused, uintptr_t unused2,
-                         InvokeType unused3)
+                                InvokeType unused3)
 {
   int trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
-  return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
 }
 
 static int NextDirectCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
-                                uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
+                                const CompilerDriver::MethodReference& target_method,
+                                uint32_t method_idx, uintptr_t unused,
                                 uintptr_t unused2, InvokeType unused3)
 {
   int trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
-  return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
 }
 
 static int NextSuperCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
-                               uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
-                        uintptr_t unused2, InvokeType unused3)
+                               const CompilerDriver::MethodReference& target_method,
+                               uint32_t method_idx, uintptr_t unused,
+                               uintptr_t unused2, InvokeType unused3)
 {
   int trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
-  return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
 }
 
 static int NextVCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
-                           uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
+                           const CompilerDriver::MethodReference& target_method,
+                           uint32_t method_idx, uintptr_t unused,
                            uintptr_t unused2, InvokeType unused3)
 {
   int trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
-  return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
 }
 
 static int NextInterfaceCallInsnWithAccessCheck(CompilationUnit* cu,
                                                 CallInfo* info, int state,
-                                         uint32_t dex_idx, uint32_t unused,
-                                         uintptr_t unused2, uintptr_t unused3,
-                                         InvokeType unused4)
+                                                const CompilerDriver::MethodReference& target_method,
+                                                uint32_t unused,
+                                                uintptr_t unused2, uintptr_t unused3,
+                                                InvokeType unused4)
 {
   int trampoline = ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
-  return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
 }
 
 int Mir2Lir::LoadArgRegs(CallInfo* info, int call_state,
-                         NextCallInsn next_call_insn, uint32_t dex_idx,
-                         uint32_t method_idx, uintptr_t direct_code,
+                         NextCallInsn next_call_insn,
+                         const CompilerDriver::MethodReference& target_method,
+                         uint32_t vtable_idx, uintptr_t direct_code,
                          uintptr_t direct_method, InvokeType type, bool skip_this)
 {
   int last_arg_reg = TargetReg(kArg3);
@@ -605,8 +632,8 @@
       }
       LoadValueDirectFixed(rl_arg, next_reg);
     }
-    call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
-                 direct_code, direct_method, type);
+    call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
+                                direct_code, direct_method, type);
   }
   return call_state;
 }
@@ -620,7 +647,8 @@
  */
 int Mir2Lir::GenDalvikArgsNoRange(CallInfo* info,
                                   int call_state, LIR** pcrLabel, NextCallInsn next_call_insn,
-                                  uint32_t dex_idx, uint32_t method_idx, uintptr_t direct_code,
+                                  const CompilerDriver::MethodReference& target_method,
+                                  uint32_t vtable_idx, uintptr_t direct_code,
                                   uintptr_t direct_method, InvokeType type, bool skip_this)
 {
   RegLocation rl_arg;
@@ -629,8 +657,8 @@
   if (info->num_arg_words == 0)
     return call_state;
 
-  call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
-                           direct_code, direct_method, type);
+  call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
+                              direct_code, direct_method, type);
 
   DCHECK_LE(info->num_arg_words, 5);
   if (info->num_arg_words > 3) {
@@ -650,13 +678,13 @@
         // kArg2 & rArg3 can safely be used here
         reg = TargetReg(kArg3);
         LoadWordDisp(TargetReg(kSp), SRegOffset(rl_arg.s_reg_low) + 4, reg);
-        call_state = next_call_insn(cu_, info, call_state, dex_idx,
-                                 method_idx, direct_code, direct_method, type);
+        call_state = next_call_insn(cu_, info, call_state, target_method,
+                                    vtable_idx, direct_code, direct_method, type);
       }
       StoreBaseDisp(TargetReg(kSp), (next_use + 1) * 4, reg, kWord);
       StoreBaseDisp(TargetReg(kSp), 16 /* (3+1)*4 */, reg, kWord);
-      call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
-                               direct_code, direct_method, type);
+      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
+                                  direct_code, direct_method, type);
       next_use++;
     }
     // Loop through the rest
@@ -676,8 +704,8 @@
         } else {
           LoadValueDirectFixed(rl_arg, low_reg);
         }
-        call_state = next_call_insn(cu_, info, call_state, dex_idx,
-                                 method_idx, direct_code, direct_method, type);
+        call_state = next_call_insn(cu_, info, call_state, target_method,
+                                    vtable_idx, direct_code, direct_method, type);
       }
       int outs_offset = (next_use + 1) * 4;
       if (rl_arg.wide) {
@@ -687,14 +715,14 @@
         StoreWordDisp(TargetReg(kSp), outs_offset, low_reg);
         next_use++;
       }
-      call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
                                direct_code, direct_method, type);
     }
   }
 
   call_state = LoadArgRegs(info, call_state, next_call_insn,
-                          dex_idx, method_idx, direct_code, direct_method,
-                          type, skip_this);
+                           target_method, vtable_idx, direct_code, direct_method,
+                           type, skip_this);
 
   if (pcrLabel) {
     *pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
@@ -718,15 +746,16 @@
  *
  */
 int Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
-                                LIR** pcrLabel, NextCallInsn next_call_insn, uint32_t dex_idx,
-                                uint32_t method_idx, uintptr_t direct_code, uintptr_t direct_method,
+                                LIR** pcrLabel, NextCallInsn next_call_insn,
+                                const CompilerDriver::MethodReference& target_method,
+                                uint32_t vtable_idx, uintptr_t direct_code, uintptr_t direct_method,
                                 InvokeType type, bool skip_this)
 {
 
   // If we can treat it as non-range (Jumbo ops will use range form)
   if (info->num_arg_words <= 5)
     return GenDalvikArgsNoRange(info, call_state, pcrLabel,
-                                next_call_insn, dex_idx, method_idx,
+                                next_call_insn, target_method, vtable_idx,
                                 direct_code, direct_method, type, skip_this);
   /*
    * First load the non-register arguments.  Both forms expect all
@@ -772,31 +801,31 @@
     } else {
       // Use vldm/vstm pair using kArg3 as a temp
       int regs_left = std::min(info->num_arg_words - 3, 16);
-      call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
                                direct_code, direct_method, type);
       OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), start_offset);
       LIR* ld = OpVldm(TargetReg(kArg3), regs_left);
       //TUNING: loosen barrier
       ld->def_mask = ENCODE_ALL;
       SetMemRefType(ld, true /* is_load */, kDalvikReg);
-      call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
                                direct_code, direct_method, type);
       OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), 4 /* Method* */ + (3 * 4));
-      call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
                                direct_code, direct_method, type);
       LIR* st = OpVstm(TargetReg(kArg3), regs_left);
       SetMemRefType(st, false /* is_load */, kDalvikReg);
       st->def_mask = ENCODE_ALL;
-      call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
                                direct_code, direct_method, type);
     }
   }
 
   call_state = LoadArgRegs(info, call_state, next_call_insn,
-                          dex_idx, method_idx, direct_code, direct_method,
-                          type, skip_this);
+                           target_method, vtable_idx, direct_code, direct_method,
+                           type, skip_this);
 
-  call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+  call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
                            direct_code, direct_method, type);
   if (pcrLabel) {
     *pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
@@ -1150,6 +1179,10 @@
     // TODO - add Mips implementation
     return false;
   }
+  if (cu_->instruction_set == kX86 && is_object) {
+    // TODO: fix X86, it exhausts registers for card marking.
+    return false;
+  }
   // Unused - RegLocation rl_src_unsafe = info->args[0];
   RegLocation rl_src_obj = info->args[1];  // Object
   RegLocation rl_src_offset = info->args[2];  // long low
@@ -1193,20 +1226,27 @@
    * method.  By doing this during basic block construction, we can also
    * take advantage of/generate new useful dataflow info.
    */
-  std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
-  if (tgt_method.find(" java.lang") != std::string::npos) {
+  StringPiece tgt_methods_declaring_class(
+      cu_->dex_file->GetMethodDeclaringClassDescriptor(cu_->dex_file->GetMethodId(info->index)));
+  if (tgt_methods_declaring_class.starts_with("Ljava/lang/Double;")) {
+    std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
     if (tgt_method == "long java.lang.Double.doubleToRawLongBits(double)") {
       return GenInlinedDoubleCvt(info);
     }
     if (tgt_method == "double java.lang.Double.longBitsToDouble(long)") {
       return GenInlinedDoubleCvt(info);
     }
+  } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/Float;")) {
+    std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
     if (tgt_method == "int java.lang.Float.float_to_raw_int_bits(float)") {
       return GenInlinedFloatCvt(info);
     }
     if (tgt_method == "float java.lang.Float.intBitsToFloat(int)") {
       return GenInlinedFloatCvt(info);
     }
+  } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/Math;") ||
+             tgt_methods_declaring_class.starts_with("Ljava/lang/StrictMath;")) {
+    std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
     if (tgt_method == "int java.lang.Math.abs(int)" ||
         tgt_method == "int java.lang.StrictMath.abs(int)") {
       return GenInlinedAbsInt(info);
@@ -1227,6 +1267,8 @@
         tgt_method == "double java.lang.StrictMath.sqrt(double)") {
       return GenInlinedSqrt(info);
     }
+  } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/String;")) {
+    std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
     if (tgt_method == "char java.lang.String.charAt(int)") {
       return GenInlinedCharAt(info);
     }
@@ -1245,10 +1287,13 @@
     if (tgt_method == "int java.lang.String.length()") {
       return GenInlinedStringIsEmptyOrLength(info, false /* is_empty */);
     }
+  } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/Thread;")) {
+    std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
     if (tgt_method == "java.lang.Thread java.lang.Thread.currentThread()") {
       return GenInlinedCurrentThread(info);
     }
-  } else if (tgt_method.find(" sun.misc.Unsafe") != std::string::npos) {
+  } else if (tgt_methods_declaring_class.starts_with("Lsun/misc/Unsafe;")) {
+    std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
     if (tgt_method == "boolean sun.misc.Unsafe.compareAndSwapInt(java.lang.Object, long, int, int)") {
       return GenInlinedCas32(info, false);
     }
@@ -1327,20 +1372,24 @@
   // Explicit register usage
   LockCallTemps();
 
-  uint32_t dex_method_idx = info->index;
+  DexCompilationUnit* cUnit = mir_graph_->GetCurrentDexCompilationUnit();
+  CompilerDriver::MethodReference target_method(cUnit->GetDexFile(), info->index);
   int vtable_idx;
   uintptr_t direct_code;
   uintptr_t direct_method;
   bool skip_this;
-  bool fast_path = cu_->compiler_driver->ComputeInvokeInfo(
-      dex_method_idx, current_dalvik_offset_, mir_graph_->GetCurrentDexCompilationUnit(), info->type, vtable_idx,
-      direct_code, direct_method) && !SLOW_INVOKE_PATH;
+  bool fast_path =
+      cu_->compiler_driver->ComputeInvokeInfo(mir_graph_->GetCurrentDexCompilationUnit(),
+                                              current_dalvik_offset_,
+                                              info->type, target_method,
+                                              vtable_idx,
+                                              direct_code, direct_method,
+                                              true) && !SLOW_INVOKE_PATH;
   if (info->type == kInterface) {
     if (fast_path) {
       p_null_ck = &null_ck;
     }
-    next_call_insn = fast_path ? NextInterfaceCallInsn
-                            : NextInterfaceCallInsnWithAccessCheck;
+    next_call_insn = fast_path ? NextInterfaceCallInsn : NextInterfaceCallInsnWithAccessCheck;
     skip_this = false;
   } else if (info->type == kDirect) {
     if (fast_path) {
@@ -1362,20 +1411,20 @@
   }
   if (!info->is_range) {
     call_state = GenDalvikArgsNoRange(info, call_state, p_null_ck,
-                                     next_call_insn, dex_method_idx,
-                                     vtable_idx, direct_code, direct_method,
-                                     original_type, skip_this);
+                                      next_call_insn, target_method,
+                                      vtable_idx, direct_code, direct_method,
+                                      original_type, skip_this);
   } else {
     call_state = GenDalvikArgsRange(info, call_state, p_null_ck,
-                                   next_call_insn, dex_method_idx, vtable_idx,
-                                   direct_code, direct_method, original_type,
-                                   skip_this);
+                                    next_call_insn, target_method, vtable_idx,
+                                    direct_code, direct_method, original_type,
+                                    skip_this);
   }
   // Finish up any of the call sequence not interleaved in arg loading
   while (call_state >= 0) {
-    call_state = next_call_insn(cu_, info, call_state, dex_method_idx,
-                             vtable_idx, direct_code, direct_method,
-                             original_type);
+    call_state = next_call_insn(cu_, info, call_state, target_method,
+                                vtable_idx, direct_code, direct_method,
+                                original_type);
   }
   LIR* call_inst;
   if (cu_->instruction_set != kX86) {
diff --git a/src/compiler/dex/quick/gen_loadstore.cc b/src/compiler/dex/quick/gen_loadstore.cc
index 1cebd31..085f7f5 100644
--- a/src/compiler/dex/quick/gen_loadstore.cc
+++ b/src/compiler/dex/quick/gen_loadstore.cc
@@ -16,6 +16,7 @@
 
 #include "compiler/dex/compiler_ir.h"
 #include "compiler/dex/compiler_internals.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "invoke_type.h"
 
 namespace art {
diff --git a/src/compiler/dex/quick/mips/assemble_mips.cc b/src/compiler/dex/quick/mips/assemble_mips.cc
index 5223a0e..002a23e 100644
--- a/src/compiler/dex/quick/mips/assemble_mips.cc
+++ b/src/compiler/dex/quick/mips/assemble_mips.cc
@@ -15,6 +15,7 @@
  */
 
 #include "codegen_mips.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "mips_lir.h"
 
 namespace art {
diff --git a/src/compiler/dex/quick/mips/call_mips.cc b/src/compiler/dex/quick/mips/call_mips.cc
index b53d1e3..9f1d314 100644
--- a/src/compiler/dex/quick/mips/call_mips.cc
+++ b/src/compiler/dex/quick/mips/call_mips.cc
@@ -17,6 +17,7 @@
 /* This file contains codegen for the Mips ISA */
 
 #include "codegen_mips.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "mips_lir.h"
 #include "oat/runtime/oat_support_entrypoints.h"
 
diff --git a/src/compiler/dex/quick/mips/codegen_mips.h b/src/compiler/dex/quick/mips/codegen_mips.h
index db262a8..9fa8f77 100644
--- a/src/compiler/dex/quick/mips/codegen_mips.h
+++ b/src/compiler/dex/quick/mips/codegen_mips.h
@@ -28,139 +28,139 @@
     MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
 
     // Required for target - codegen utilities.
-    virtual bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
+    bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
                                     RegLocation rl_dest, int lit);
-    virtual int LoadHelper(int offset);
-    virtual LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
-    virtual LIR* LoadBaseDispWide(int rBase, int displacement, int r_dest_lo, int r_dest_hi,
+    int LoadHelper(int offset);
+    LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
+    LIR* LoadBaseDispWide(int rBase, int displacement, int r_dest_lo, int r_dest_hi,
                                   int s_reg);
-    virtual LIR* LoadBaseIndexed(int rBase, int r_index, int r_dest, int scale, OpSize size);
-    virtual LIR* LoadBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
+    LIR* LoadBaseIndexed(int rBase, int r_index, int r_dest, int scale, OpSize size);
+    LIR* LoadBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
                                      int r_dest, int r_dest_hi, OpSize size, int s_reg);
-    virtual LIR* LoadConstantNoClobber(int r_dest, int value);
-    virtual LIR* LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value);
-    virtual LIR* StoreBaseDisp(int rBase, int displacement, int r_src, OpSize size);
-    virtual LIR* StoreBaseDispWide(int rBase, int displacement, int r_src_lo, int r_src_hi);
-    virtual LIR* StoreBaseIndexed(int rBase, int r_index, int r_src, int scale, OpSize size);
-    virtual LIR* StoreBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
+    LIR* LoadConstantNoClobber(int r_dest, int value);
+    LIR* LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value);
+    LIR* StoreBaseDisp(int rBase, int displacement, int r_src, OpSize size);
+    LIR* StoreBaseDispWide(int rBase, int displacement, int r_src_lo, int r_src_hi);
+    LIR* StoreBaseIndexed(int rBase, int r_index, int r_src, int scale, OpSize size);
+    LIR* StoreBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
                                       int r_src, int r_src_hi, OpSize size, int s_reg);
-    virtual void MarkGCCard(int val_reg, int tgt_addr_reg);
+    void MarkGCCard(int val_reg, int tgt_addr_reg);
 
     // Required for target - register utilities.
-    virtual bool IsFpReg(int reg);
-    virtual bool SameRegType(int reg1, int reg2);
-    virtual int AllocTypedTemp(bool fp_hint, int reg_class);
-    virtual int AllocTypedTempPair(bool fp_hint, int reg_class);
-    virtual int S2d(int low_reg, int high_reg);
-    virtual int TargetReg(SpecialTargetRegister reg);
-    virtual RegisterInfo* GetRegInfo(int reg);
-    virtual RegLocation GetReturnAlt();
-    virtual RegLocation GetReturnWideAlt();
-    virtual RegLocation LocCReturn();
-    virtual RegLocation LocCReturnDouble();
-    virtual RegLocation LocCReturnFloat();
-    virtual RegLocation LocCReturnWide();
-    virtual uint32_t FpRegMask();
-    virtual uint64_t GetRegMaskCommon(int reg);
-    virtual void AdjustSpillMask();
-    virtual void ClobberCalleeSave();
-    virtual void FlushReg(int reg);
-    virtual void FlushRegWide(int reg1, int reg2);
-    virtual void FreeCallTemps();
-    virtual void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
-    virtual void LockCallTemps();
-    virtual void MarkPreservedSingle(int v_reg, int reg);
-    virtual void CompilerInitializeRegAlloc();
+    bool IsFpReg(int reg);
+    bool SameRegType(int reg1, int reg2);
+    int AllocTypedTemp(bool fp_hint, int reg_class);
+    int AllocTypedTempPair(bool fp_hint, int reg_class);
+    int S2d(int low_reg, int high_reg);
+    int TargetReg(SpecialTargetRegister reg);
+    RegisterInfo* GetRegInfo(int reg);
+    RegLocation GetReturnAlt();
+    RegLocation GetReturnWideAlt();
+    RegLocation LocCReturn();
+    RegLocation LocCReturnDouble();
+    RegLocation LocCReturnFloat();
+    RegLocation LocCReturnWide();
+    uint32_t FpRegMask();
+    uint64_t GetRegMaskCommon(int reg);
+    void AdjustSpillMask();
+    void ClobberCalleeSave();
+    void FlushReg(int reg);
+    void FlushRegWide(int reg1, int reg2);
+    void FreeCallTemps();
+    void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
+    void LockCallTemps();
+    void MarkPreservedSingle(int v_reg, int reg);
+    void CompilerInitializeRegAlloc();
 
     // Required for target - miscellaneous.
-    virtual AssemblerStatus AssembleInstructions(uintptr_t start_addr);
-    virtual void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix);
-    virtual void SetupTargetResourceMasks(LIR* lir);
-    virtual const char* GetTargetInstFmt(int opcode);
-    virtual const char* GetTargetInstName(int opcode);
-    virtual std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr);
-    virtual uint64_t GetPCUseDefEncoding();
-    virtual uint64_t GetTargetInstFlags(int opcode);
-    virtual int GetInsnSize(LIR* lir);
-    virtual bool IsUnconditionalBranch(LIR* lir);
+    AssemblerStatus AssembleInstructions(uintptr_t start_addr);
+    void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix);
+    void SetupTargetResourceMasks(LIR* lir);
+    const char* GetTargetInstFmt(int opcode);
+    const char* GetTargetInstName(int opcode);
+    std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr);
+    uint64_t GetPCUseDefEncoding();
+    uint64_t GetTargetInstFlags(int opcode);
+    int GetInsnSize(LIR* lir);
+    bool IsUnconditionalBranch(LIR* lir);
 
     // Required for target - Dalvik-level generators.
-    virtual void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
+    void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
                                    RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenArrayObjPut(int opt_flags, RegLocation rl_array, RegLocation rl_index,
+    void GenArrayObjPut(int opt_flags, RegLocation rl_array, RegLocation rl_index,
                                 RegLocation rl_src, int scale);
-    virtual void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
+    void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
                              RegLocation rl_index, RegLocation rl_dest, int scale);
-    virtual void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
+    void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
                              RegLocation rl_index, RegLocation rl_src, int scale);
-    virtual void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
+    void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
                                    RegLocation rl_src1, RegLocation rl_shift);
-    virtual void GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenAndLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
+    void GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenAndLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
                                   RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
+    void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
                                  RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
+    void GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
                           RegLocation rl_src2);
-    virtual void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
-    virtual bool GenInlinedCas32(CallInfo* info, bool need_write_barrier);
-    virtual bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
-    virtual bool GenInlinedSqrt(CallInfo* info);
-    virtual void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
-    virtual void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenXorLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base, int offset,
+    void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
+    bool GenInlinedCas32(CallInfo* info, bool need_write_barrier);
+    bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
+    bool GenInlinedSqrt(CallInfo* info);
+    void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
+    void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenXorLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base, int offset,
                                 ThrowKind kind);
-    virtual RegLocation GenDivRem(RegLocation rl_dest, int reg_lo, int reg_hi, bool is_div);
-    virtual RegLocation GenDivRemLit(RegLocation rl_dest, int reg_lo, int lit, bool is_div);
-    virtual void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenDivZeroCheck(int reg_lo, int reg_hi);
-    virtual void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
-    virtual void GenExitSequence();
-    virtual void GenFillArrayData(uint32_t table_offset, RegLocation rl_src);
-    virtual void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
-    virtual void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
-    virtual void GenSelect(BasicBlock* bb, MIR* mir);
-    virtual void GenMemBarrier(MemBarrierKind barrier_kind);
-    virtual void GenMonitorEnter(int opt_flags, RegLocation rl_src);
-    virtual void GenMonitorExit(int opt_flags, RegLocation rl_src);
-    virtual void GenMoveException(RegLocation rl_dest);
-    virtual void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit,
+    RegLocation GenDivRem(RegLocation rl_dest, int reg_lo, int reg_hi, bool is_div);
+    RegLocation GenDivRemLit(RegLocation rl_dest, int reg_lo, int lit, bool is_div);
+    void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenDivZeroCheck(int reg_lo, int reg_hi);
+    void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
+    void GenExitSequence();
+    void GenFillArrayData(uint32_t table_offset, RegLocation rl_src);
+    void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
+    void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
+    void GenSelect(BasicBlock* bb, MIR* mir);
+    void GenMemBarrier(MemBarrierKind barrier_kind);
+    void GenMonitorEnter(int opt_flags, RegLocation rl_src);
+    void GenMonitorExit(int opt_flags, RegLocation rl_src);
+    void GenMoveException(RegLocation rl_dest);
+    void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit,
                                                int first_bit, int second_bit);
-    virtual void GenNegDouble(RegLocation rl_dest, RegLocation rl_src);
-    virtual void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
-    virtual void GenPackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
-    virtual void GenSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
-    virtual void GenSpecialCase(BasicBlock* bb, MIR* mir, SpecialCaseHandler special_case);
+    void GenNegDouble(RegLocation rl_dest, RegLocation rl_src);
+    void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
+    void GenPackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
+    void GenSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
+    void GenSpecialCase(BasicBlock* bb, MIR* mir, SpecialCaseHandler special_case);
 
     // Required for target - single operation generators.
-    virtual LIR* OpUnconditionalBranch(LIR* target);
-    virtual LIR* OpCmpBranch(ConditionCode cond, int src1, int src2, LIR* target);
-    virtual LIR* OpCmpImmBranch(ConditionCode cond, int reg, int check_value, LIR* target);
-    virtual LIR* OpCondBranch(ConditionCode cc, LIR* target);
-    virtual LIR* OpDecAndBranch(ConditionCode c_code, int reg, LIR* target);
-    virtual LIR* OpFpRegCopy(int r_dest, int r_src);
-    virtual LIR* OpIT(ConditionCode cond, const char* guide);
-    virtual LIR* OpMem(OpKind op, int rBase, int disp);
-    virtual LIR* OpPcRelLoad(int reg, LIR* target);
-    virtual LIR* OpReg(OpKind op, int r_dest_src);
-    virtual LIR* OpRegCopy(int r_dest, int r_src);
-    virtual LIR* OpRegCopyNoInsert(int r_dest, int r_src);
-    virtual LIR* OpRegImm(OpKind op, int r_dest_src1, int value);
-    virtual LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset);
-    virtual LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
-    virtual LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
-    virtual LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
-    virtual LIR* OpTestSuspend(LIR* target);
-    virtual LIR* OpThreadMem(OpKind op, int thread_offset);
-    virtual LIR* OpVldm(int rBase, int count);
-    virtual LIR* OpVstm(int rBase, int count);
-    virtual void OpLea(int rBase, int reg1, int reg2, int scale, int offset);
-    virtual void OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, int src_hi);
-    virtual void OpTlsCmp(int offset, int val);
+    LIR* OpUnconditionalBranch(LIR* target);
+    LIR* OpCmpBranch(ConditionCode cond, int src1, int src2, LIR* target);
+    LIR* OpCmpImmBranch(ConditionCode cond, int reg, int check_value, LIR* target);
+    LIR* OpCondBranch(ConditionCode cc, LIR* target);
+    LIR* OpDecAndBranch(ConditionCode c_code, int reg, LIR* target);
+    LIR* OpFpRegCopy(int r_dest, int r_src);
+    LIR* OpIT(ConditionCode cond, const char* guide);
+    LIR* OpMem(OpKind op, int rBase, int disp);
+    LIR* OpPcRelLoad(int reg, LIR* target);
+    LIR* OpReg(OpKind op, int r_dest_src);
+    LIR* OpRegCopy(int r_dest, int r_src);
+    LIR* OpRegCopyNoInsert(int r_dest, int r_src);
+    LIR* OpRegImm(OpKind op, int r_dest_src1, int value);
+    LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset);
+    LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
+    LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
+    LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
+    LIR* OpTestSuspend(LIR* target);
+    LIR* OpThreadMem(OpKind op, int thread_offset);
+    LIR* OpVldm(int rBase, int count);
+    LIR* OpVstm(int rBase, int count);
+    void OpLea(int rBase, int reg1, int reg2, int scale, int offset);
+    void OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, int src_hi);
+    void OpTlsCmp(int offset, int val);
 
     LIR* LoadBaseDispBody(int rBase, int displacement, int r_dest, int r_dest_hi, OpSize size,
                           int s_reg);
diff --git a/src/compiler/dex/quick/mips/fp_mips.cc b/src/compiler/dex/quick/mips/fp_mips.cc
index 5ddec00..f384da1 100644
--- a/src/compiler/dex/quick/mips/fp_mips.cc
+++ b/src/compiler/dex/quick/mips/fp_mips.cc
@@ -16,6 +16,7 @@
 
 #include "codegen_mips.h"
 #include "mips_lir.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "oat/runtime/oat_support_entrypoints.h"
 
 namespace art {
diff --git a/src/compiler/dex/quick/mips/int_mips.cc b/src/compiler/dex/quick/mips/int_mips.cc
index fbff397..fe9e83f 100644
--- a/src/compiler/dex/quick/mips/int_mips.cc
+++ b/src/compiler/dex/quick/mips/int_mips.cc
@@ -17,6 +17,7 @@
 /* This file contains codegen for the Mips ISA */
 
 #include "codegen_mips.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "mips_lir.h"
 #include "mirror/array.h"
 #include "oat/runtime/oat_support_entrypoints.h"
diff --git a/src/compiler/dex/quick/mips/target_mips.cc b/src/compiler/dex/quick/mips/target_mips.cc
index 46a625e..356104c 100644
--- a/src/compiler/dex/quick/mips/target_mips.cc
+++ b/src/compiler/dex/quick/mips/target_mips.cc
@@ -16,6 +16,7 @@
 
 #include "codegen_mips.h"
 #include "compiler/dex/compiler_internals.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "mips_lir.h"
 
 #include <string>
diff --git a/src/compiler/dex/quick/mips/utility_mips.cc b/src/compiler/dex/quick/mips/utility_mips.cc
index 5f9f8c5..257b0f6 100644
--- a/src/compiler/dex/quick/mips/utility_mips.cc
+++ b/src/compiler/dex/quick/mips/utility_mips.cc
@@ -15,6 +15,7 @@
  */
 
 #include "codegen_mips.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "mips_lir.h"
 
 namespace art {
diff --git a/src/compiler/dex/quick/mir_to_lir-inl.h b/src/compiler/dex/quick/mir_to_lir-inl.h
new file mode 100644
index 0000000..f754692
--- /dev/null
+++ b/src/compiler/dex/quick/mir_to_lir-inl.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2013 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_COMPILER_DEX_QUICK_MIR_TO_LIR_INL_H_
+#define ART_SRC_COMPILER_DEX_QUICK_MIR_TO_LIR_INL_H_
+
+#include "mir_to_lir.h"
+
+#include "compiler/dex/compiler_internals.h"
+
+namespace art {
+
+/* Mark a temp register as dead.  Does not affect allocation state. */
+inline void Mir2Lir::ClobberBody(RegisterInfo* p) {
+  if (p->is_temp) {
+    DCHECK(!(p->live && p->dirty))  << "Live & dirty temp in clobber";
+    p->live = false;
+    p->s_reg = INVALID_SREG;
+    p->def_start = NULL;
+    p->def_end = NULL;
+    if (p->pair) {
+      p->pair = false;
+      Clobber(p->partner);
+    }
+  }
+}
+
+inline LIR* Mir2Lir::RawLIR(int dalvik_offset, int opcode, int op0,
+                            int op1, int op2, int op3, int op4, LIR* target) {
+  LIR* insn = static_cast<LIR*>(arena_->NewMem(sizeof(LIR), true, ArenaAllocator::kAllocLIR));
+  insn->dalvik_offset = dalvik_offset;
+  insn->opcode = opcode;
+  insn->operands[0] = op0;
+  insn->operands[1] = op1;
+  insn->operands[2] = op2;
+  insn->operands[3] = op3;
+  insn->operands[4] = op4;
+  insn->target = target;
+  SetupResourceMasks(insn);
+  if ((opcode == kPseudoTargetLabel) || (opcode == kPseudoSafepointPC) ||
+      (opcode == kPseudoExportedPC)) {
+    // Always make labels scheduling barriers
+    insn->use_mask = insn->def_mask = ENCODE_ALL;
+  }
+  return insn;
+}
+
+/*
+ * The following are building blocks to construct low-level IRs with 0 - 4
+ * operands.
+ */
+inline LIR* Mir2Lir::NewLIR0(int opcode) {
+  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & NO_OPERAND))
+      << GetTargetInstName(opcode) << " " << opcode << " "
+      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
+      << current_dalvik_offset_;
+  LIR* insn = RawLIR(current_dalvik_offset_, opcode);
+  AppendLIR(insn);
+  return insn;
+}
+
+inline LIR* Mir2Lir::NewLIR1(int opcode, int dest) {
+  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_UNARY_OP))
+      << GetTargetInstName(opcode) << " " << opcode << " "
+      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
+      << current_dalvik_offset_;
+  LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest);
+  AppendLIR(insn);
+  return insn;
+}
+
+inline LIR* Mir2Lir::NewLIR2(int opcode, int dest, int src1) {
+  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_BINARY_OP))
+      << GetTargetInstName(opcode) << " " << opcode << " "
+      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
+      << current_dalvik_offset_;
+  LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1);
+  AppendLIR(insn);
+  return insn;
+}
+
+inline LIR* Mir2Lir::NewLIR3(int opcode, int dest, int src1, int src2) {
+  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_TERTIARY_OP))
+      << GetTargetInstName(opcode) << " " << opcode << " "
+      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
+      << current_dalvik_offset_;
+  LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1, src2);
+  AppendLIR(insn);
+  return insn;
+}
+
+inline LIR* Mir2Lir::NewLIR4(int opcode, int dest, int src1, int src2, int info) {
+  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_QUAD_OP))
+      << GetTargetInstName(opcode) << " " << opcode << " "
+      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
+      << current_dalvik_offset_;
+  LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1, src2, info);
+  AppendLIR(insn);
+  return insn;
+}
+
+inline LIR* Mir2Lir::NewLIR5(int opcode, int dest, int src1, int src2, int info1,
+                             int info2) {
+  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_QUIN_OP))
+      << GetTargetInstName(opcode) << " " << opcode << " "
+      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
+      << current_dalvik_offset_;
+  LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1, src2, info1, info2);
+  AppendLIR(insn);
+  return insn;
+}
+
+/*
+ * Mark the corresponding bit(s).
+ */
+inline void Mir2Lir::SetupRegMask(uint64_t* mask, int reg) {
+  *mask |= GetRegMaskCommon(reg);
+}
+
+/*
+ * Set up the proper fields in the resource mask
+ */
+inline void Mir2Lir::SetupResourceMasks(LIR* lir) {
+  int opcode = lir->opcode;
+
+  if (opcode <= 0) {
+    lir->use_mask = lir->def_mask = 0;
+    return;
+  }
+
+  uint64_t flags = GetTargetInstFlags(opcode);
+
+  if (flags & NEEDS_FIXUP) {
+    lir->flags.pcRelFixup = true;
+  }
+
+  /* Get the starting size of the instruction's template */
+  lir->flags.size = GetInsnSize(lir);
+
+  /* Set up the mask for resources that are updated */
+  if (flags & (IS_LOAD | IS_STORE)) {
+    /* Default to heap - will catch specialized classes later */
+    SetMemRefType(lir, flags & IS_LOAD, kHeapRef);
+  }
+
+  /*
+   * Conservatively assume the branch here will call out a function that in
+   * turn will trash everything.
+   */
+  if (flags & IS_BRANCH) {
+    lir->def_mask = lir->use_mask = ENCODE_ALL;
+    return;
+  }
+
+  if (flags & REG_DEF0) {
+    SetupRegMask(&lir->def_mask, lir->operands[0]);
+  }
+
+  if (flags & REG_DEF1) {
+    SetupRegMask(&lir->def_mask, lir->operands[1]);
+  }
+
+
+  if (flags & SETS_CCODES) {
+    lir->def_mask |= ENCODE_CCODE;
+  }
+
+  if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
+    int i;
+
+    for (i = 0; i < 4; i++) {
+      if (flags & (1 << (kRegUse0 + i))) {
+        SetupRegMask(&lir->use_mask, lir->operands[i]);
+      }
+    }
+  }
+
+  if (flags & USES_CCODES) {
+    lir->use_mask |= ENCODE_CCODE;
+  }
+
+  // Handle target-specific actions
+  SetupTargetResourceMasks(lir);
+}
+
+}  // namespace art
+
+#endif  // ART_SRC_COMPILER_DEX_QUICK_MIR_TO_LIR_INL_H_
diff --git a/src/compiler/dex/quick/mir_to_lir.cc b/src/compiler/dex/quick/mir_to_lir.cc
index 481078d..754aae4 100644
--- a/src/compiler/dex/quick/mir_to_lir.cc
+++ b/src/compiler/dex/quick/mir_to_lir.cc
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-#include "object_utils.h"
-
 #include "compiler/dex/compiler_internals.h"
-#include "compiler/dex/dataflow_iterator.h"
+#include "compiler/dex/dataflow_iterator-inl.h"
+#include "mir_to_lir-inl.h"
+#include "object_utils.h"
 
 namespace art {
 
@@ -184,10 +184,10 @@
       GenMonitorExit(opt_flags, rl_src[0]);
       break;
 
-    case Instruction::CHECK_CAST:
-      GenCheckCast(vB, rl_src[0]);
+    case Instruction::CHECK_CAST: {
+      GenCheckCast(mir->offset, vB, rl_src[0]);
       break;
-
+    }
     case Instruction::INSTANCE_OF:
       GenInstanceof(vC, rl_dest, rl_src[0]);
       break;
diff --git a/src/compiler/dex/quick/mir_to_lir.h b/src/compiler/dex/quick/mir_to_lir.h
index 21a0aac..9eb4524 100644
--- a/src/compiler/dex/quick/mir_to_lir.h
+++ b/src/compiler/dex/quick/mir_to_lir.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_SRC_COMPILER_DEX_QUICK_CODEGEN_H_
-#define ART_SRC_COMPILER_DEX_QUICK_CODEGEN_H_
+#ifndef ART_SRC_COMPILER_DEX_QUICK_MIR_TO_LIR_H_
+#define ART_SRC_COMPILER_DEX_QUICK_MIR_TO_LIR_H_
 
 #include "invoke_type.h"
 #include "compiled_method.h"
@@ -24,6 +24,7 @@
 #include "compiler/dex/backend.h"
 #include "compiler/dex/growable_array.h"
 #include "compiler/dex/arena_allocator.h"
+#include "compiler/driver/compiler_driver.h"
 #include "safe_map.h"
 
 namespace art {
@@ -98,7 +99,8 @@
 class MIRGraph;
 class Mir2Lir;
 
-typedef int (*NextCallInsn)(CompilationUnit*, CallInfo*, int, uint32_t dex_idx,
+typedef int (*NextCallInsn)(CompilationUnit*, CallInfo*, int,
+                            const CompilerDriver::MethodReference& target_method,
                             uint32_t method_idx, uintptr_t direct_code,
                             uintptr_t direct_method, InvokeType type);
 
@@ -312,8 +314,10 @@
     void DumpRegPool(RegisterInfo* p, int num_regs);
     void DumpCoreRegPool();
     void DumpFpRegPool();
-    void ClobberBody(RegisterInfo* p);
-    void Clobber(int reg);
+    /* Mark a temp register as dead.  Does not affect allocation state. */
+    void Clobber(int reg) {
+      ClobberBody(GetRegInfo(reg));
+    }
     void ClobberSRegBody(RegisterInfo* p, int num_regs, int s_reg);
     void ClobberSReg(int s_reg);
     int SRegToPMap(int s_reg);
@@ -337,7 +341,6 @@
     RegisterInfo* IsPromoted(int reg);
     bool IsDirty(int reg);
     void LockTemp(int reg);
-    void ResetDefBody(RegisterInfo* p);
     void ResetDef(int reg);
     void NullifyRange(LIR *start, LIR *finish, int s_reg1, int s_reg2);
     void MarkDef(RegLocation rl, LIR *start, LIR *finish);
@@ -410,7 +413,8 @@
     void GenThrow(RegLocation rl_src);
     void GenInstanceof(uint32_t type_idx, RegLocation rl_dest,
                        RegLocation rl_src);
-    void GenCheckCast(uint32_t type_idx, RegLocation rl_src);
+    void GenCheckCast(uint32_t insn_idx, uint32_t type_idx,
+                      RegLocation rl_src);
     void GenLong3Addr(OpKind first_op, OpKind second_op, RegLocation rl_dest,
                       RegLocation rl_src1, RegLocation rl_src2);
     void GenShiftOpLong(Instruction::Code opcode, RegLocation rl_dest,
@@ -462,11 +466,15 @@
     void GenInvoke(CallInfo* info);
     void FlushIns(RegLocation* ArgLocs, RegLocation rl_method);
     int GenDalvikArgsNoRange(CallInfo* info, int call_state, LIR** pcrLabel,
-                             NextCallInsn next_call_insn, uint32_t dex_idx, uint32_t method_idx,
+                             NextCallInsn next_call_insn,
+                             const CompilerDriver::MethodReference& target_method,
+                             uint32_t vtable_idx,
                              uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
                              bool skip_this);
     int GenDalvikArgsRange(CallInfo* info, int call_state, LIR** pcrLabel,
-                           NextCallInsn next_call_insn, uint32_t dex_idx, uint32_t method_idx,
+                           NextCallInsn next_call_insn,
+                           const CompilerDriver::MethodReference& target_method,
+                           uint32_t vtable_idx,
                            uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
                            bool skip_this);
     RegLocation InlineTarget(CallInfo* info);
@@ -486,7 +494,9 @@
                              bool is_volatile, bool is_ordered);
     bool GenIntrinsic(CallInfo* info);
     int LoadArgRegs(CallInfo* info, int call_state,
-                    NextCallInsn next_call_insn, uint32_t dex_idx, uint32_t method_idx,
+                    NextCallInsn next_call_insn,
+                    const CompilerDriver::MethodReference& target_method,
+                    uint32_t vtable_idx,
                     uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
                     bool skip_this);
 
@@ -681,11 +691,6 @@
     // Temp workaround
     void Workaround7250540(RegLocation rl_dest, int value);
 
-    // TODO: add accessors for these.
-    LIR* literal_list_;                        // Constants.
-    LIR* method_literal_list_;                 // Method literals requiring patching.
-    LIR* code_literal_list_;                   // Code literals requiring patching.
-
   protected:
     Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
 
@@ -693,6 +698,28 @@
       return cu_;
     }
 
+  private:
+    void GenInstanceofFinal(bool use_declaring_class, uint32_t type_idx, RegLocation rl_dest,
+                            RegLocation rl_src);
+    void GenInstanceofCallingHelper(bool needs_access_check, bool type_known_final,
+                                    bool type_known_abstract, bool use_declaring_class,
+                                    bool can_assume_type_is_in_dex_cache,
+                                    uint32_t type_idx, RegLocation rl_dest,
+                                    RegLocation rl_src);
+
+    void ClobberBody(RegisterInfo* p);
+    void ResetDefBody(RegisterInfo* p) {
+      p->def_start = NULL;
+      p->def_end = NULL;
+    }
+
+  public:
+    // TODO: add accessors for these.
+    LIR* literal_list_;                        // Constants.
+    LIR* method_literal_list_;                 // Method literals requiring patching.
+    LIR* code_literal_list_;                   // Code literals requiring patching.
+
+  protected:
     CompilationUnit* const cu_;
     MIRGraph* const mir_graph_;
     GrowableArray<SwitchTable*> switch_tables_;
@@ -749,4 +776,4 @@
 
 }  // namespace art
 
-#endif // ART_SRC_COMPILER_DEX_QUICK_CODEGEN_H_
+#endif  //ART_SRC_COMPILER_DEX_QUICK_MIR_TO_LIR_H_
diff --git a/src/compiler/dex/quick/ralloc_util.cc b/src/compiler/dex/quick/ralloc_util.cc
index 30ed1b7..8e0dba3 100644
--- a/src/compiler/dex/quick/ralloc_util.cc
+++ b/src/compiler/dex/quick/ralloc_util.cc
@@ -18,6 +18,7 @@
 
 #include "compiler/dex/compiler_ir.h"
 #include "compiler/dex/compiler_internals.h"
+#include "mir_to_lir-inl.h"
 
 namespace art {
 
@@ -84,28 +85,6 @@
   DumpRegPool(reg_pool_->FPRegs, reg_pool_->num_fp_regs);
 }
 
-/* Mark a temp register as dead.  Does not affect allocation state. */
-void Mir2Lir::ClobberBody(RegisterInfo* p)
-{
-  if (p->is_temp) {
-    DCHECK(!(p->live && p->dirty))  << "Live & dirty temp in clobber";
-    p->live = false;
-    p->s_reg = INVALID_SREG;
-    p->def_start = NULL;
-    p->def_end = NULL;
-    if (p->pair) {
-      p->pair = false;
-      Clobber(p->partner);
-    }
-  }
-}
-
-/* Mark a temp register as dead.  Does not affect allocation state. */
-void Mir2Lir::Clobber(int reg)
-{
-  ClobberBody(GetRegInfo(reg));
-}
-
 void Mir2Lir::ClobberSRegBody(RegisterInfo* p, int num_regs, int s_reg)
 {
   int i;
@@ -555,12 +534,6 @@
   LOG(FATAL) << "Tried to lock a non-existant temp: r" << reg;
 }
 
-void Mir2Lir::ResetDefBody(RegisterInfo* p)
-{
-  p->def_start = NULL;
-  p->def_end = NULL;
-}
-
 void Mir2Lir::ResetDef(int reg)
 {
   ResetDefBody(GetRegInfo(reg));
diff --git a/src/compiler/dex/quick/x86/assemble_x86.cc b/src/compiler/dex/quick/x86/assemble_x86.cc
index f7c1594..83dabe6 100644
--- a/src/compiler/dex/quick/x86/assemble_x86.cc
+++ b/src/compiler/dex/quick/x86/assemble_x86.cc
@@ -15,6 +15,7 @@
  */
 
 #include "codegen_x86.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "x86_lir.h"
 
 namespace art {
diff --git a/src/compiler/dex/quick/x86/call_x86.cc b/src/compiler/dex/quick/x86/call_x86.cc
index 614a72d..1e37b2f 100644
--- a/src/compiler/dex/quick/x86/call_x86.cc
+++ b/src/compiler/dex/quick/x86/call_x86.cc
@@ -17,6 +17,7 @@
 /* This file contains codegen for the X86 ISA */
 
 #include "codegen_x86.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "x86_lir.h"
 
 namespace art {
diff --git a/src/compiler/dex/quick/x86/codegen_x86.h b/src/compiler/dex/quick/x86/codegen_x86.h
index 99e5148..9050656 100644
--- a/src/compiler/dex/quick/x86/codegen_x86.h
+++ b/src/compiler/dex/quick/x86/codegen_x86.h
@@ -28,139 +28,139 @@
     X86Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
 
     // Required for target - codegen helpers.
-    virtual bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
+    bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
                                     RegLocation rl_dest, int lit);
-    virtual int LoadHelper(int offset);
-    virtual LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
-    virtual LIR* LoadBaseDispWide(int rBase, int displacement, int r_dest_lo, int r_dest_hi,
+    int LoadHelper(int offset);
+    LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
+    LIR* LoadBaseDispWide(int rBase, int displacement, int r_dest_lo, int r_dest_hi,
                                   int s_reg);
-    virtual LIR* LoadBaseIndexed(int rBase, int r_index, int r_dest, int scale, OpSize size);
-    virtual LIR* LoadBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
+    LIR* LoadBaseIndexed(int rBase, int r_index, int r_dest, int scale, OpSize size);
+    LIR* LoadBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
                                      int r_dest, int r_dest_hi, OpSize size, int s_reg);
-    virtual LIR* LoadConstantNoClobber(int r_dest, int value);
-    virtual LIR* LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value);
-    virtual LIR* StoreBaseDisp(int rBase, int displacement, int r_src, OpSize size);
-    virtual LIR* StoreBaseDispWide(int rBase, int displacement, int r_src_lo, int r_src_hi);
-    virtual LIR* StoreBaseIndexed(int rBase, int r_index, int r_src, int scale, OpSize size);
-    virtual LIR* StoreBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
+    LIR* LoadConstantNoClobber(int r_dest, int value);
+    LIR* LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value);
+    LIR* StoreBaseDisp(int rBase, int displacement, int r_src, OpSize size);
+    LIR* StoreBaseDispWide(int rBase, int displacement, int r_src_lo, int r_src_hi);
+    LIR* StoreBaseIndexed(int rBase, int r_index, int r_src, int scale, OpSize size);
+    LIR* StoreBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
                                       int r_src, int r_src_hi, OpSize size, int s_reg);
-    virtual void MarkGCCard(int val_reg, int tgt_addr_reg);
+    void MarkGCCard(int val_reg, int tgt_addr_reg);
 
     // Required for target - register utilities.
-    virtual bool IsFpReg(int reg);
-    virtual bool SameRegType(int reg1, int reg2);
-    virtual int AllocTypedTemp(bool fp_hint, int reg_class);
-    virtual int AllocTypedTempPair(bool fp_hint, int reg_class);
-    virtual int S2d(int low_reg, int high_reg);
-    virtual int TargetReg(SpecialTargetRegister reg);
-    virtual RegisterInfo* GetRegInfo(int reg);
-    virtual RegLocation GetReturnAlt();
-    virtual RegLocation GetReturnWideAlt();
-    virtual RegLocation LocCReturn();
-    virtual RegLocation LocCReturnDouble();
-    virtual RegLocation LocCReturnFloat();
-    virtual RegLocation LocCReturnWide();
-    virtual uint32_t FpRegMask();
-    virtual uint64_t GetRegMaskCommon(int reg);
-    virtual void AdjustSpillMask();
-    virtual void ClobberCalleeSave();
-    virtual void FlushReg(int reg);
-    virtual void FlushRegWide(int reg1, int reg2);
-    virtual void FreeCallTemps();
-    virtual void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
-    virtual void LockCallTemps();
-    virtual void MarkPreservedSingle(int v_reg, int reg);
-    virtual void CompilerInitializeRegAlloc();
+    bool IsFpReg(int reg);
+    bool SameRegType(int reg1, int reg2);
+    int AllocTypedTemp(bool fp_hint, int reg_class);
+    int AllocTypedTempPair(bool fp_hint, int reg_class);
+    int S2d(int low_reg, int high_reg);
+    int TargetReg(SpecialTargetRegister reg);
+    RegisterInfo* GetRegInfo(int reg);
+    RegLocation GetReturnAlt();
+    RegLocation GetReturnWideAlt();
+    RegLocation LocCReturn();
+    RegLocation LocCReturnDouble();
+    RegLocation LocCReturnFloat();
+    RegLocation LocCReturnWide();
+    uint32_t FpRegMask();
+    uint64_t GetRegMaskCommon(int reg);
+    void AdjustSpillMask();
+    void ClobberCalleeSave();
+    void FlushReg(int reg);
+    void FlushRegWide(int reg1, int reg2);
+    void FreeCallTemps();
+    void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
+    void LockCallTemps();
+    void MarkPreservedSingle(int v_reg, int reg);
+    void CompilerInitializeRegAlloc();
 
     // Required for target - miscellaneous.
-    virtual AssemblerStatus AssembleInstructions(uintptr_t start_addr);
-    virtual void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix);
-    virtual void SetupTargetResourceMasks(LIR* lir);
-    virtual const char* GetTargetInstFmt(int opcode);
-    virtual const char* GetTargetInstName(int opcode);
-    virtual std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr);
-    virtual uint64_t GetPCUseDefEncoding();
-    virtual uint64_t GetTargetInstFlags(int opcode);
-    virtual int GetInsnSize(LIR* lir);
-    virtual bool IsUnconditionalBranch(LIR* lir);
+    AssemblerStatus AssembleInstructions(uintptr_t start_addr);
+    void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix);
+    void SetupTargetResourceMasks(LIR* lir);
+    const char* GetTargetInstFmt(int opcode);
+    const char* GetTargetInstName(int opcode);
+    std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr);
+    uint64_t GetPCUseDefEncoding();
+    uint64_t GetTargetInstFlags(int opcode);
+    int GetInsnSize(LIR* lir);
+    bool IsUnconditionalBranch(LIR* lir);
 
     // Required for target - Dalvik-level generators.
-    virtual void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
+    void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
                                    RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenArrayObjPut(int opt_flags, RegLocation rl_array,
+    void GenArrayObjPut(int opt_flags, RegLocation rl_array,
                                 RegLocation rl_index, RegLocation rl_src, int scale);
-    virtual void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
+    void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
                              RegLocation rl_index, RegLocation rl_dest, int scale);
-    virtual void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
+    void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
                              RegLocation rl_index, RegLocation rl_src, int scale);
-    virtual void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
+    void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
                                    RegLocation rl_src1, RegLocation rl_shift);
-    virtual void GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenAndLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
+    void GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenAndLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
                                   RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
+    void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
                                  RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
+    void GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
                           RegLocation rl_src2);
-    virtual void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
-    virtual bool GenInlinedCas32(CallInfo* info, bool need_write_barrier);
-    virtual bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
-    virtual bool GenInlinedSqrt(CallInfo* info);
-    virtual void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
-    virtual void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenXorLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base, int offset,
+    void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
+    bool GenInlinedCas32(CallInfo* info, bool need_write_barrier);
+    bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
+    bool GenInlinedSqrt(CallInfo* info);
+    void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
+    void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenXorLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base, int offset,
                                 ThrowKind kind);
-    virtual RegLocation GenDivRem(RegLocation rl_dest, int reg_lo, int reg_hi, bool is_div);
-    virtual RegLocation GenDivRemLit(RegLocation rl_dest, int reg_lo, int lit, bool is_div);
-    virtual void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenDivZeroCheck(int reg_lo, int reg_hi);
-    virtual void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
-    virtual void GenExitSequence();
-    virtual void GenFillArrayData(uint32_t table_offset, RegLocation rl_src);
-    virtual void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
-    virtual void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
-    virtual void GenSelect(BasicBlock* bb, MIR* mir);
-    virtual void GenMemBarrier(MemBarrierKind barrier_kind);
-    virtual void GenMonitorEnter(int opt_flags, RegLocation rl_src);
-    virtual void GenMonitorExit(int opt_flags, RegLocation rl_src);
-    virtual void GenMoveException(RegLocation rl_dest);
-    virtual void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result,
+    RegLocation GenDivRem(RegLocation rl_dest, int reg_lo, int reg_hi, bool is_div);
+    RegLocation GenDivRemLit(RegLocation rl_dest, int reg_lo, int lit, bool is_div);
+    void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenDivZeroCheck(int reg_lo, int reg_hi);
+    void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
+    void GenExitSequence();
+    void GenFillArrayData(uint32_t table_offset, RegLocation rl_src);
+    void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
+    void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
+    void GenSelect(BasicBlock* bb, MIR* mir);
+    void GenMemBarrier(MemBarrierKind barrier_kind);
+    void GenMonitorEnter(int opt_flags, RegLocation rl_src);
+    void GenMonitorExit(int opt_flags, RegLocation rl_src);
+    void GenMoveException(RegLocation rl_dest);
+    void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result,
                                                int lit, int first_bit, int second_bit);
-    virtual void GenNegDouble(RegLocation rl_dest, RegLocation rl_src);
-    virtual void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
-    virtual void GenPackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
-    virtual void GenSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
-    virtual void GenSpecialCase(BasicBlock* bb, MIR* mir, SpecialCaseHandler special_case);
+    void GenNegDouble(RegLocation rl_dest, RegLocation rl_src);
+    void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
+    void GenPackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
+    void GenSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
+    void GenSpecialCase(BasicBlock* bb, MIR* mir, SpecialCaseHandler special_case);
 
     // Single operation generators.
-    virtual LIR* OpUnconditionalBranch(LIR* target);
-    virtual LIR* OpCmpBranch(ConditionCode cond, int src1, int src2, LIR* target);
-    virtual LIR* OpCmpImmBranch(ConditionCode cond, int reg, int check_value, LIR* target);
-    virtual LIR* OpCondBranch(ConditionCode cc, LIR* target);
-    virtual LIR* OpDecAndBranch(ConditionCode c_code, int reg, LIR* target);
-    virtual LIR* OpFpRegCopy(int r_dest, int r_src);
-    virtual LIR* OpIT(ConditionCode cond, const char* guide);
-    virtual LIR* OpMem(OpKind op, int rBase, int disp);
-    virtual LIR* OpPcRelLoad(int reg, LIR* target);
-    virtual LIR* OpReg(OpKind op, int r_dest_src);
-    virtual LIR* OpRegCopy(int r_dest, int r_src);
-    virtual LIR* OpRegCopyNoInsert(int r_dest, int r_src);
-    virtual LIR* OpRegImm(OpKind op, int r_dest_src1, int value);
-    virtual LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset);
-    virtual LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
-    virtual LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
-    virtual LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
-    virtual LIR* OpTestSuspend(LIR* target);
-    virtual LIR* OpThreadMem(OpKind op, int thread_offset);
-    virtual LIR* OpVldm(int rBase, int count);
-    virtual LIR* OpVstm(int rBase, int count);
-    virtual void OpLea(int rBase, int reg1, int reg2, int scale, int offset);
-    virtual void OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, int src_hi);
-    virtual void OpTlsCmp(int offset, int val);
+    LIR* OpUnconditionalBranch(LIR* target);
+    LIR* OpCmpBranch(ConditionCode cond, int src1, int src2, LIR* target);
+    LIR* OpCmpImmBranch(ConditionCode cond, int reg, int check_value, LIR* target);
+    LIR* OpCondBranch(ConditionCode cc, LIR* target);
+    LIR* OpDecAndBranch(ConditionCode c_code, int reg, LIR* target);
+    LIR* OpFpRegCopy(int r_dest, int r_src);
+    LIR* OpIT(ConditionCode cond, const char* guide);
+    LIR* OpMem(OpKind op, int rBase, int disp);
+    LIR* OpPcRelLoad(int reg, LIR* target);
+    LIR* OpReg(OpKind op, int r_dest_src);
+    LIR* OpRegCopy(int r_dest, int r_src);
+    LIR* OpRegCopyNoInsert(int r_dest, int r_src);
+    LIR* OpRegImm(OpKind op, int r_dest_src1, int value);
+    LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset);
+    LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
+    LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
+    LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
+    LIR* OpTestSuspend(LIR* target);
+    LIR* OpThreadMem(OpKind op, int thread_offset);
+    LIR* OpVldm(int rBase, int count);
+    LIR* OpVstm(int rBase, int count);
+    void OpLea(int rBase, int reg1, int reg2, int scale, int offset);
+    void OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, int src_hi);
+    void OpTlsCmp(int offset, int val);
 
     void OpRegThreadMem(OpKind op, int r_dest, int thread_offset);
     void SpillCoreRegs();
diff --git a/src/compiler/dex/quick/x86/fp_x86.cc b/src/compiler/dex/quick/x86/fp_x86.cc
index db2cf28..3341e28 100644
--- a/src/compiler/dex/quick/x86/fp_x86.cc
+++ b/src/compiler/dex/quick/x86/fp_x86.cc
@@ -15,6 +15,7 @@
  */
 
 #include "codegen_x86.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "x86_lir.h"
 
 namespace art {
diff --git a/src/compiler/dex/quick/x86/int_x86.cc b/src/compiler/dex/quick/x86/int_x86.cc
index b2ee949..fffb900 100644
--- a/src/compiler/dex/quick/x86/int_x86.cc
+++ b/src/compiler/dex/quick/x86/int_x86.cc
@@ -18,6 +18,7 @@
 
 #include "codegen_x86.h"
 #include "mirror/array.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "x86_lir.h"
 
 namespace art {
diff --git a/src/compiler/dex/quick/x86/target_x86.cc b/src/compiler/dex/quick/x86/target_x86.cc
index e6a49f8..9110b70 100644
--- a/src/compiler/dex/quick/x86/target_x86.cc
+++ b/src/compiler/dex/quick/x86/target_x86.cc
@@ -16,6 +16,7 @@
 
 #include "codegen_x86.h"
 #include "compiler/dex/compiler_internals.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "x86_lir.h"
 
 #include <string>
diff --git a/src/compiler/dex/quick/x86/utility_x86.cc b/src/compiler/dex/quick/x86/utility_x86.cc
index 45c0e9c..82466d4 100644
--- a/src/compiler/dex/quick/x86/utility_x86.cc
+++ b/src/compiler/dex/quick/x86/utility_x86.cc
@@ -15,6 +15,7 @@
  */
 
 #include "codegen_x86.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "x86_lir.h"
 
 namespace art {
diff --git a/src/compiler/dex/ssa_transformation.cc b/src/compiler/dex/ssa_transformation.cc
index a90d705..4182072 100644
--- a/src/compiler/dex/ssa_transformation.cc
+++ b/src/compiler/dex/ssa_transformation.cc
@@ -15,7 +15,7 @@
  */
 
 #include "compiler_internals.h"
-#include "dataflow_iterator.h"
+#include "dataflow_iterator-inl.h"
 
 #define NOTVISITED (-1)
 
diff --git a/src/compiler/dex/vreg_analysis.cc b/src/compiler/dex/vreg_analysis.cc
index d4223f1..b941140 100644
--- a/src/compiler/dex/vreg_analysis.cc
+++ b/src/compiler/dex/vreg_analysis.cc
@@ -15,7 +15,7 @@
  */
 
 #include "compiler_internals.h"
-#include "dataflow_iterator.h"
+#include "compiler/dex/dataflow_iterator-inl.h"
 
 namespace art {
 
@@ -292,18 +292,10 @@
           is_high |= is_phi && rl_temp.wide && rl_temp.high_word;
         }
         /*
-         * TODO: cleaner fix
-         * We don't normally expect to see a Dalvik register
-         * definition used both as a floating point and core
-         * value.  However, the instruction rewriting that occurs
-         * during verification can eliminate some type information,
-         * leaving us confused.  The real fix here is either to
-         * add explicit type information to Dalvik byte codes,
-         * or to recognize THROW_VERIFICATION_ERROR as
-         * an unconditional branch and support dead code elimination.
-         * As a workaround we can detect this situation and
-         * disable register promotion (which is the only thing that
-         * relies on distinctions between core and fp usages.
+         * We don't normally expect to see a Dalvik register definition used both as a
+         * floating point and core value, though technically it could happen with constants.
+         * Until we have proper typing, detect this situation and disable register promotion
+         * (which relies on the distinction between core a fp usages).
          */
         if ((defined_fp && (defined_core | defined_ref)) &&
             ((cu_->disable_opt & (1 << kPromoteRegs)) == 0)) {
diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc
index 6985172..b04e5b1 100644
--- a/src/compiler/driver/compiler_driver.cc
+++ b/src/compiler/driver/compiler_driver.cc
@@ -24,6 +24,7 @@
 #include "base/stl_util.h"
 #include "base/timing_logger.h"
 #include "class_linker.h"
+#include "compiler/stubs/stubs.h"
 #include "dex_compilation_unit.h"
 #include "dex_file-inl.h"
 #include "jni_internal.h"
@@ -34,7 +35,7 @@
 #include "gc/space.h"
 #include "mirror/class_loader.h"
 #include "mirror/class-inl.h"
-#include "mirror/dex_cache.h"
+#include "mirror/dex_cache-inl.h"
 #include "mirror/field-inl.h"
 #include "mirror/abstract_method-inl.h"
 #include "mirror/object-inl.h"
@@ -72,7 +73,8 @@
         resolved_types_(0), unresolved_types_(0),
         resolved_instance_fields_(0), unresolved_instance_fields_(0),
         resolved_local_static_fields_(0), resolved_static_fields_(0), unresolved_static_fields_(0),
-        type_based_devirtualization_(0) {
+        type_based_devirtualization_(0),
+        safe_casts_(0), not_safe_casts_(0) {
     for (size_t i = 0; i <= kMaxInvokeType; i++) {
       resolved_methods_[i] = 0;
       unresolved_methods_[i] = 0;
@@ -91,8 +93,14 @@
              "static fields resolved");
     DumpStat(resolved_local_static_fields_, resolved_static_fields_ + unresolved_static_fields_,
              "static fields local to a class");
-    DumpStat(type_based_devirtualization_,virtual_made_direct_[kInterface] + virtual_made_direct_[kVirtual]
-             - type_based_devirtualization_, "sharpened calls based on type information");
+    DumpStat(safe_casts_, not_safe_casts_, "check-casts removed based on type information");
+    // Note, the code below subtracts the stat value so that when added to the stat value we have
+    // 100% of samples. TODO: clean this up.
+    DumpStat(type_based_devirtualization_,
+             resolved_methods_[kVirtual] + unresolved_methods_[kVirtual] +
+             resolved_methods_[kInterface] + unresolved_methods_[kInterface] -
+             type_based_devirtualization_,
+             "virtual/interface calls made direct based on type information");
 
     for (size_t i = 0; i <= kMaxInvokeType; i++) {
       std::ostringstream oss;
@@ -184,40 +192,61 @@
     unresolved_static_fields_++;
   }
 
+  // Indicate that type information from the verifier led to devirtualization.
   void PreciseTypeDevirtualization() {
     STATS_LOCK();
     type_based_devirtualization_++;
   }
+
+  // Indicate that a method of the given type was resolved at compile time.
   void ResolvedMethod(InvokeType type) {
     DCHECK_LE(type, kMaxInvokeType);
     STATS_LOCK();
     resolved_methods_[type]++;
   }
 
+  // Indicate that a method of the given type was unresolved at compile time as it was in an
+  // unknown dex file.
   void UnresolvedMethod(InvokeType type) {
     DCHECK_LE(type, kMaxInvokeType);
     STATS_LOCK();
     unresolved_methods_[type]++;
   }
 
+  // Indicate that a type of virtual method dispatch has been converted into a direct method
+  // dispatch.
   void VirtualMadeDirect(InvokeType type) {
-    DCHECK_LE(type, kMaxInvokeType);
+    DCHECK(type == kVirtual || type == kInterface || type == kSuper);
     STATS_LOCK();
     virtual_made_direct_[type]++;
   }
 
+  // Indicate that a method of the given type was able to call directly into boot.
   void DirectCallsToBoot(InvokeType type) {
     DCHECK_LE(type, kMaxInvokeType);
     STATS_LOCK();
     direct_calls_to_boot_[type]++;
   }
 
+  // Indicate that a method of the given type was able to be resolved directly from boot.
   void DirectMethodsToBoot(InvokeType type) {
     DCHECK_LE(type, kMaxInvokeType);
     STATS_LOCK();
     direct_methods_to_boot_[type]++;
   }
 
+  // A check-cast could be eliminated due to verifier type analysis.
+  void SafeCast() {
+    STATS_LOCK();
+    safe_casts_++;
+  }
+
+  // A check-cast couldn't be eliminated due to verifier type analysis.
+  void NotASafeCast() {
+    STATS_LOCK();
+    not_safe_casts_++;
+  }
+
  private:
   Mutex stats_lock_;
 
@@ -245,6 +274,9 @@
   size_t direct_calls_to_boot_[kMaxInvokeType + 1];
   size_t direct_methods_to_boot_[kMaxInvokeType + 1];
 
+  size_t safe_casts_;
+  size_t not_safe_casts_;
+
   DISALLOW_COPY_AND_ASSIGN(AOTCompilationStats);
 };
 
@@ -292,8 +324,8 @@
 }
 
 CompilerDriver::CompilerDriver(CompilerBackend compiler_backend, InstructionSet instruction_set,
-                               bool image, size_t thread_count, bool support_debugging,
-                               const std::set<std::string>* image_classes,
+                               bool image, DescriptorSet* image_classes,
+                               size_t thread_count, bool support_debugging,
                                bool dump_stats, bool dump_timings)
     : compiler_backend_(compiler_backend),
       instruction_set_(instruction_set),
@@ -301,18 +333,20 @@
       compiled_classes_lock_("compiled classes lock"),
       compiled_methods_lock_("compiled method lock"),
       image_(image),
+      image_classes_(image_classes),
       thread_count_(thread_count),
       support_debugging_(support_debugging),
       start_ns_(0),
       stats_(new AOTCompilationStats),
       dump_stats_(dump_stats),
       dump_timings_(dump_timings),
-      image_classes_(image_classes),
       compiler_library_(NULL),
       compiler_(NULL),
       compiler_context_(NULL),
       jni_compiler_(NULL),
-      compiler_get_method_code_addr_(NULL)
+      compiler_enable_auto_elf_loading_(NULL),
+      compiler_get_method_code_addr_(NULL),
+      support_boot_image_fixup_(true)
 {
   std::string compiler_so_name(MakeCompilerSoName(compiler_backend_));
   compiler_library_ = dlopen(compiler_so_name.c_str(), RTLD_LAZY);
@@ -347,7 +381,7 @@
 
   CHECK(!Runtime::Current()->IsStarted());
   if (!image_) {
-    CHECK(image_classes_ == NULL);
+    CHECK(image_classes_.get() == NULL);
   }
 }
 
@@ -416,6 +450,66 @@
   return res;
 }
 
+const std::vector<uint8_t>* CompilerDriver::CreatePortableResolutionTrampoline() const {
+  switch (instruction_set_) {
+    case kArm:
+    case kThumb2:
+      return arm::CreatePortableResolutionTrampoline();
+    case kMips:
+      return mips::CreatePortableResolutionTrampoline();
+    case kX86:
+      return x86::CreatePortableResolutionTrampoline();
+    default:
+      LOG(FATAL) << "Unknown InstructionSet: " << instruction_set_;
+      return NULL;
+  }
+}
+
+const std::vector<uint8_t>* CompilerDriver::CreateQuickResolutionTrampoline() const {
+  switch (instruction_set_) {
+    case kArm:
+    case kThumb2:
+      return arm::CreateQuickResolutionTrampoline();
+    case kMips:
+      return mips::CreateQuickResolutionTrampoline();
+    case kX86:
+      return x86::CreateQuickResolutionTrampoline();
+    default:
+      LOG(FATAL) << "Unknown InstructionSet: " << instruction_set_;
+      return NULL;
+  }
+}
+
+const std::vector<uint8_t>* CompilerDriver::CreateInterpreterToInterpreterEntry() const {
+  switch (instruction_set_) {
+    case kArm:
+    case kThumb2:
+      return arm::CreateInterpreterToInterpreterEntry();
+    case kMips:
+      return mips::CreateInterpreterToInterpreterEntry();
+    case kX86:
+      return x86::CreateInterpreterToInterpreterEntry();
+    default:
+      LOG(FATAL) << "Unknown InstructionSet: " << instruction_set_;
+      return NULL;
+  }
+}
+
+const std::vector<uint8_t>* CompilerDriver::CreateInterpreterToQuickEntry() const {
+  switch (instruction_set_) {
+    case kArm:
+    case kThumb2:
+      return arm::CreateInterpreterToQuickEntry();
+    case kMips:
+      return mips::CreateInterpreterToQuickEntry();
+    case kX86:
+      return x86::CreateInterpreterToQuickEntry();
+    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());
@@ -483,20 +577,199 @@
 
 void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
                                 ThreadPool& thread_pool, TimingLogger& timings) {
+  LoadImageClasses(timings);
+
   Resolve(class_loader, dex_files, thread_pool, timings);
 
   Verify(class_loader, dex_files, thread_pool, timings);
 
   InitializeClasses(class_loader, dex_files, thread_pool, timings);
+
+  UpdateImageClasses(timings);
 }
 
-bool CompilerDriver::IsImageClass(const std::string& descriptor) const {
-  if (image_classes_ == NULL) {
-    return false;
+bool CompilerDriver::IsImageClass(const char* descriptor) const {
+  DCHECK(descriptor != NULL);
+  if (image_classes_.get() == NULL) {
+    return true;
   }
   return image_classes_->find(descriptor) != image_classes_->end();
 }
 
+static void ResolveExceptionsForMethod(MethodHelper* mh,
+    std::set<std::pair<uint16_t, const DexFile*> >& exceptions_to_resolve)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  const DexFile::CodeItem* code_item = mh->GetCodeItem();
+  if (code_item == NULL) {
+    return;  // native or abstract method
+  }
+  if (code_item->tries_size_ == 0) {
+    return;  // nothing to process
+  }
+  const byte* encoded_catch_handler_list = DexFile::GetCatchHandlerData(*code_item, 0);
+  size_t num_encoded_catch_handlers = DecodeUnsignedLeb128(&encoded_catch_handler_list);
+  for (size_t i = 0; i < num_encoded_catch_handlers; i++) {
+    int32_t encoded_catch_handler_size = DecodeSignedLeb128(&encoded_catch_handler_list);
+    bool has_catch_all = false;
+    if (encoded_catch_handler_size <= 0) {
+      encoded_catch_handler_size = -encoded_catch_handler_size;
+      has_catch_all = true;
+    }
+    for (int32_t j = 0; j < encoded_catch_handler_size; j++) {
+      uint16_t encoded_catch_handler_handlers_type_idx =
+          DecodeUnsignedLeb128(&encoded_catch_handler_list);
+      // Add to set of types to resolve if not already in the dex cache resolved types
+      if (!mh->IsResolvedTypeIdx(encoded_catch_handler_handlers_type_idx)) {
+        exceptions_to_resolve.insert(
+            std::pair<uint16_t, const DexFile*>(encoded_catch_handler_handlers_type_idx,
+                                                &mh->GetDexFile()));
+      }
+      // ignore address associated with catch handler
+      DecodeUnsignedLeb128(&encoded_catch_handler_list);
+    }
+    if (has_catch_all) {
+      // ignore catch all address
+      DecodeUnsignedLeb128(&encoded_catch_handler_list);
+    }
+  }
+}
+
+static bool ResolveCatchBlockExceptionsClassVisitor(mirror::Class* c, void* arg)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  std::set<std::pair<uint16_t, const DexFile*> >* exceptions_to_resolve =
+      reinterpret_cast<std::set<std::pair<uint16_t, const DexFile*> >*>(arg);
+  MethodHelper mh;
+  for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
+    mirror::AbstractMethod* m = c->GetVirtualMethod(i);
+    mh.ChangeMethod(m);
+    ResolveExceptionsForMethod(&mh, *exceptions_to_resolve);
+  }
+  for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
+    mirror::AbstractMethod* m = c->GetDirectMethod(i);
+    mh.ChangeMethod(m);
+    ResolveExceptionsForMethod(&mh, *exceptions_to_resolve);
+  }
+  return true;
+}
+
+static bool RecordImageClassesVisitor(mirror::Class* klass, void* arg)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  CompilerDriver::DescriptorSet* image_classes =
+      reinterpret_cast<CompilerDriver::DescriptorSet*>(arg);
+  image_classes->insert(ClassHelper(klass).GetDescriptor());
+  return true;
+}
+
+// Make a list of descriptors for classes to include in the image
+void CompilerDriver::LoadImageClasses(TimingLogger& timings)
+      LOCKS_EXCLUDED(Locks::mutator_lock_) {
+  if (image_classes_.get() == NULL) {
+    return;
+  }
+
+  // Make a first class to load all classes explicitly listed in the file
+  Thread* self = Thread::Current();
+  ScopedObjectAccess soa(self);
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  typedef DescriptorSet::iterator It;  // TODO: C++0x auto
+  for (It it = image_classes_->begin(), end = image_classes_->end(); it != end;) {
+    std::string descriptor(*it);
+    SirtRef<mirror::Class> klass(self, class_linker->FindSystemClass(descriptor.c_str()));
+    if (klass.get() == NULL) {
+      image_classes_->erase(it++);
+      LOG(WARNING) << "Failed to find class " << descriptor;
+      Thread::Current()->ClearException();
+    } else {
+      ++it;
+    }
+  }
+
+  // Resolve exception classes referenced by the loaded classes. The catch logic assumes
+  // exceptions are resolved by the verifier when there is a catch block in an interested method.
+  // Do this here so that exception classes appear to have been specified image classes.
+  std::set<std::pair<uint16_t, const DexFile*> > unresolved_exception_types;
+  SirtRef<mirror::Class> java_lang_Throwable(self,
+                                     class_linker->FindSystemClass("Ljava/lang/Throwable;"));
+  do {
+    unresolved_exception_types.clear();
+    class_linker->VisitClasses(ResolveCatchBlockExceptionsClassVisitor,
+                               &unresolved_exception_types);
+    typedef std::set<std::pair<uint16_t, const DexFile*> >::const_iterator It;  // TODO: C++0x auto
+    for (It it = unresolved_exception_types.begin(),
+         end = unresolved_exception_types.end();
+         it != end; ++it) {
+      uint16_t exception_type_idx = it->first;
+      const DexFile* dex_file = it->second;
+      mirror::DexCache* dex_cache = class_linker->FindDexCache(*dex_file);
+      mirror:: ClassLoader* class_loader = NULL;
+      SirtRef<mirror::Class> klass(self, class_linker->ResolveType(*dex_file, exception_type_idx,
+                                                                   dex_cache, class_loader));
+      if (klass.get() == NULL) {
+        const DexFile::TypeId& type_id = dex_file->GetTypeId(exception_type_idx);
+        const char* descriptor = dex_file->GetTypeDescriptor(type_id);
+        LOG(FATAL) << "Failed to resolve class " << descriptor;
+      }
+      DCHECK(java_lang_Throwable->IsAssignableFrom(klass.get()));
+    }
+    // Resolving exceptions may load classes that reference more exceptions, iterate until no
+    // more are found
+  } while (!unresolved_exception_types.empty());
+
+  // We walk the roots looking for classes so that we'll pick up the
+  // above classes plus any classes them depend on such super
+  // classes, interfaces, and the required ClassLinker roots.
+  class_linker->VisitClasses(RecordImageClassesVisitor, image_classes_.get());
+
+  CHECK_NE(image_classes_->size(), 0U);
+  timings.AddSplit("LoadImageClasses");
+}
+
+static void MaybeAddToImageClasses(mirror::Class* klass, CompilerDriver::DescriptorSet* image_classes)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  while (!klass->IsObjectClass()) {
+    ClassHelper kh(klass);
+    const char* descriptor = kh.GetDescriptor();
+    std::pair<CompilerDriver::DescriptorSet::iterator, bool> result =
+        image_classes->insert(descriptor);
+    if (result.second) {
+      LOG(INFO) << "Adding " << descriptor << " to image classes";
+    } else {
+      return;
+    }
+    for (size_t i = 0; i < kh.NumDirectInterfaces(); ++i) {
+      MaybeAddToImageClasses(kh.GetDirectInterface(i), image_classes);
+    }
+    if (klass->IsArrayClass()) {
+      MaybeAddToImageClasses(klass->GetComponentType(), image_classes);
+    }
+    klass = klass->GetSuperClass();
+  }
+}
+
+void CompilerDriver::FindClinitImageClassesCallback(mirror::Object* object, void* arg) {
+  DCHECK(object != NULL);
+  DCHECK(arg != NULL);
+  CompilerDriver* compiler_driver = reinterpret_cast<CompilerDriver*>(arg);
+  MaybeAddToImageClasses(object->GetClass(), compiler_driver->image_classes_.get());
+}
+
+void CompilerDriver::UpdateImageClasses(TimingLogger& timings) {
+  if (image_classes_.get() == NULL) {
+    return;
+  }
+
+  // Update image_classes_ with classes for objects created by <clinit> methods.
+  Thread* self = Thread::Current();
+  const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter");
+  Heap* heap = Runtime::Current()->GetHeap();
+  // TODO: Image spaces only?
+  WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
+  heap->FlushAllocStack();
+  heap->GetLiveBitmap()->Walk(FindClinitImageClassesCallback, this);
+  self->EndAssertNoThreadSuspension(old_cause);
+  timings.AddSplit("UpdateImageClasses");
+}
+
 void CompilerDriver::RecordClassStatus(ClassReference ref, CompiledClass* compiled_class) {
   MutexLock mu(Thread::Current(), CompilerDriver::compiled_classes_lock_);
   compiled_classes_.Put(ref, compiled_class);
@@ -504,24 +777,19 @@
 
 bool CompilerDriver::CanAssumeTypeIsPresentInDexCache(const DexFile& dex_file,
                                                       uint32_t type_idx) {
-  ScopedObjectAccess soa(Thread::Current());
-  mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
-  if (!IsImage()) {
-    stats_->TypeNotInDexCache();
-    return false;
-  }
-  mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
-  if (resolved_class == NULL) {
-    stats_->TypeNotInDexCache();
-    return false;
-  }
-  bool result = IsImageClass(ClassHelper(resolved_class).GetDescriptor());
-  if (result) {
+  if (IsImage() && IsImageClass(dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx)))) {
+    if (kIsDebugBuild) {
+      ScopedObjectAccess soa(Thread::Current());
+      mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
+      mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
+      CHECK(resolved_class != NULL);
+    }
     stats_->TypeInDexCache();
+    return true;
   } else {
     stats_->TypeNotInDexCache();
+    return false;
   }
-  return result;
 }
 
 bool CompilerDriver::CanAssumeStringIsPresentInDexCache(const DexFile& dex_file,
@@ -545,7 +813,18 @@
 }
 
 bool CompilerDriver::CanAccessTypeWithoutChecks(uint32_t referrer_idx, const DexFile& dex_file,
-                                                uint32_t type_idx) {
+                                                uint32_t type_idx,
+                                                bool* type_known_final, bool* type_known_abstract,
+                                                bool* equals_referrers_class) {
+  if (type_known_final != NULL) {
+    *type_known_final = false;
+  }
+  if (type_known_abstract != NULL) {
+    *type_known_abstract = false;
+  }
+  if (equals_referrers_class != NULL) {
+    *equals_referrers_class = false;
+  }
   ScopedObjectAccess soa(Thread::Current());
   mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
   // Get type from dex cache assuming it was populated by the verifier
@@ -555,6 +834,9 @@
     return false;  // Unknown class needs access checks.
   }
   const DexFile::MethodId& method_id = dex_file.GetMethodId(referrer_idx);
+  if (equals_referrers_class != NULL) {
+    *equals_referrers_class = (method_id.class_idx_ == type_idx);
+  }
   mirror::Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_);
   if (referrer_class == NULL) {
     stats_->TypeNeedsAccessCheck();
@@ -565,6 +847,12 @@
   bool result = referrer_class->CanAccess(resolved_class);
   if (result) {
     stats_->TypeDoesntNeedAccessCheck();
+    if (type_known_final != NULL) {
+      *type_known_final = resolved_class->IsFinal() && !resolved_class->IsArrayClass();
+    }
+    if (type_known_abstract != NULL) {
+      *type_known_abstract = resolved_class->IsAbstract() && !resolved_class->IsArrayClass();
+    }
   } else {
     stats_->TypeNeedsAccessCheck();
   }
@@ -600,9 +888,14 @@
 }
 
 static mirror::Class* ComputeCompilingMethodsClass(ScopedObjectAccess& soa,
+                                                   mirror::DexCache* dex_cache,
                                                    const DexCompilationUnit* mUnit)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::DexCache* dex_cache = mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile());
+  // The passed dex_cache is a hint, sanity check before asking the class linker that will take a
+  // lock.
+  if (dex_cache->GetDexFile() != mUnit->GetDexFile()) {
+    dex_cache = mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile());
+  }
   mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader());
   const DexFile::MethodId& referrer_method_id = mUnit->GetDexFile()->GetMethodId(mUnit->GetDexMethodIndex());
   return mUnit->GetClassLinker()->ResolveType(*mUnit->GetDexFile(), referrer_method_id.class_idx_,
@@ -639,7 +932,9 @@
   // Try to resolve field and ignore if an Incompatible Class Change Error (ie is static).
   mirror::Field* resolved_field = ComputeFieldReferencedFromCompilingMethod(soa, mUnit, field_idx);
   if (resolved_field != NULL && !resolved_field->IsStatic()) {
-    mirror::Class* referrer_class = ComputeCompilingMethodsClass(soa, mUnit);
+    mirror::Class* referrer_class =
+        ComputeCompilingMethodsClass(soa, resolved_field->GetDeclaringClass()->GetDexCache(),
+                                     mUnit);
     if (referrer_class != NULL) {
       mirror::Class* fields_class = resolved_field->GetDeclaringClass();
       bool access_ok = referrer_class->CanAccess(fields_class) &&
@@ -688,7 +983,9 @@
   // Try to resolve field and ignore if an Incompatible Class Change Error (ie isn't static).
   mirror::Field* resolved_field = ComputeFieldReferencedFromCompilingMethod(soa, mUnit, field_idx);
   if (resolved_field != NULL && resolved_field->IsStatic()) {
-    mirror::Class* referrer_class = ComputeCompilingMethodsClass(soa, mUnit);
+    mirror::Class* referrer_class =
+        ComputeCompilingMethodsClass(soa, resolved_field->GetDeclaringClass()->GetDexCache(),
+                                     mUnit);
     if (referrer_class != NULL) {
       mirror::Class* fields_class = resolved_field->GetDeclaringClass();
       if (fields_class == referrer_class) {
@@ -733,9 +1030,8 @@
           }
           // Search dex file for localized ssb index, may fail if field's class is a parent
           // of the class mentioned in the dex file and there is no dex cache entry.
-          std::string descriptor(FieldHelper(resolved_field).GetDeclaringClassDescriptor());
           const DexFile::StringId* string_id =
-          mUnit->GetDexFile()->FindStringId(descriptor);
+              mUnit->GetDexFile()->FindStringId(FieldHelper(resolved_field).GetDeclaringClassDescriptor());
           if (string_id != NULL) {
             const DexFile::TypeId* type_id =
                mUnit->GetDexFile()->FindTypeId(mUnit->GetDexFile()->GetIndexForStringId(*string_id));
@@ -764,7 +1060,8 @@
                                                    mirror::Class* referrer_class,
                                                    mirror::AbstractMethod* method,
                                                    uintptr_t& direct_code,
-                                                   uintptr_t& direct_method) {
+                                                   uintptr_t& direct_method,
+                                                   bool update_stats) {
   // For direct and static methods compute possible direct_code and direct_method values, ie
   // an address for the Method* being invoked and an address of the code for that Method*.
   // For interface calls compute a value for direct_method that is the interface method being
@@ -789,14 +1086,15 @@
     // Ensure we run the clinit trampoline unless we are invoking a static method in the same class.
     return;
   }
-  if (sharp_type != kInterface) {  // Interfaces always go via a trampoline.
-    stats_->DirectCallsToBoot(type);
+  if (update_stats) {
+    if (sharp_type != kInterface) {  // Interfaces always go via a trampoline.
+      stats_->DirectCallsToBoot(type);
+    }
+    stats_->DirectMethodsToBoot(type);
   }
-  stats_->DirectMethodsToBoot(type);
   bool compiling_boot = Runtime::Current()->GetHeap()->GetSpaces().size() == 1;
   if (compiling_boot) {
-    const bool kSupportBootImageFixup = true;
-    if (kSupportBootImageFixup) {
+    if (support_boot_image_fixup_) {
       MethodHelper mh(method);
       if (IsImageClass(mh.GetDeclaringClassDescriptor())) {
         // We can only branch directly to Methods that are resolved in the DexCache.
@@ -813,26 +1111,26 @@
   }
 }
 
-bool CompilerDriver::ComputeInvokeInfo(uint32_t method_idx,const uint32_t dex_pc,
-                                       const DexCompilationUnit* mUnit, InvokeType& type,
-                                       int& vtable_idx, uintptr_t& direct_code,
-                                       uintptr_t& direct_method) {
+bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const uint32_t dex_pc,
+                                       InvokeType& invoke_type,
+                                       MethodReference& target_method,
+                                       int& vtable_idx,
+                                       uintptr_t& direct_code, uintptr_t& direct_method,
+                                       bool update_stats) {
   ScopedObjectAccess soa(Thread::Current());
-
-  const bool kEnableVerifierBasedSharpening = true;
-  const CompilerDriver::MethodReference ref_caller(mUnit->GetDexFile(), mUnit->GetDexMethodIndex());
-  const CompilerDriver::MethodReference* ref_sharpen = verifier::MethodVerifier::GetDevirtMap(ref_caller, dex_pc);
-  bool can_devirtualize = (dex_pc != art::kDexPCNotReady) && (ref_sharpen != NULL);
   vtable_idx = -1;
   direct_code = 0;
   direct_method = 0;
   mirror::AbstractMethod* resolved_method =
-      ComputeMethodReferencedFromCompilingMethod(soa, mUnit, method_idx, type);
+      ComputeMethodReferencedFromCompilingMethod(soa, mUnit, target_method.dex_method_index,
+                                                 invoke_type);
   if (resolved_method != NULL) {
     // Don't try to fast-path if we don't understand the caller's class or this appears to be an
     // Incompatible Class Change Error.
-    mirror::Class* referrer_class = ComputeCompilingMethodsClass(soa, mUnit);
-    bool icce = resolved_method->CheckIncompatibleClassChange(type);
+    mirror::Class* referrer_class =
+        ComputeCompilingMethodsClass(soa, resolved_method->GetDeclaringClass()->GetDexCache(),
+                                     mUnit);
+    bool icce = resolved_method->CheckIncompatibleClassChange(invoke_type);
     if (referrer_class != NULL && !icce) {
       mirror::Class* methods_class = resolved_method->GetDeclaringClass();
       if (!referrer_class->CanAccess(methods_class) ||
@@ -842,74 +1140,168 @@
         // protected method being made public by implementing an interface that re-declares the
         // method public. Resort to the dex file to determine the correct class for the access
         // check.
-        const DexFile& dex_file = *referrer_class->GetDexCache()->GetDexFile();
-        methods_class =
-            mUnit->GetClassLinker()->ResolveType(dex_file,
-                                                 dex_file.GetMethodId(method_idx).class_idx_,
-                                                 referrer_class);
+        uint16_t class_idx =
+            target_method.dex_file->GetMethodId(target_method.dex_method_index).class_idx_;
+        methods_class = mUnit->GetClassLinker()->ResolveType(*target_method.dex_file,
+                                                             class_idx, referrer_class);
       }
       if (referrer_class->CanAccess(methods_class) &&
           referrer_class->CanAccessMember(methods_class, resolved_method->GetAccessFlags())) {
-        vtable_idx = resolved_method->GetMethodIndex();
-        const bool kEnableSharpening = true;
-        // Sharpen a virtual call into a direct call when the target is known.
-        bool can_sharpen = type == kVirtual && (resolved_method->IsFinal() ||
-            methods_class->IsFinal());
-        // Ensure the vtable index will be correct to dispatch in the vtable of the super class.
-        can_sharpen = can_sharpen || (type == kSuper && referrer_class != methods_class &&
-            referrer_class->IsSubClass(methods_class) &&
-            vtable_idx < methods_class->GetVTable()->GetLength() &&
-            methods_class->GetVTable()->Get(vtable_idx) == resolved_method);
+        const bool kEnableFinalBasedSharpening = true;
+        // Sharpen a virtual call into a direct call when the target is known not to have been
+        // overridden (ie is final).
+        bool can_sharpen_virtual_based_on_type =
+            (invoke_type == kVirtual) && (resolved_method->IsFinal() || methods_class->IsFinal());
+        // For invoke-super, ensure the vtable index will be correct to dispatch in the vtable of
+        // the super class.
+        bool can_sharpen_super_based_on_type = (invoke_type == kSuper) &&
+            (referrer_class != methods_class) && referrer_class->IsSubClass(methods_class) &&
+            resolved_method->GetMethodIndex() < methods_class->GetVTable()->GetLength() &&
+            (methods_class->GetVTable()->Get(resolved_method->GetMethodIndex()) == resolved_method);
 
-        if (kEnableSharpening && can_sharpen) {
-          stats_->ResolvedMethod(type);
+        if (kEnableFinalBasedSharpening && (can_sharpen_virtual_based_on_type ||
+                                            can_sharpen_super_based_on_type)) {
           // Sharpen a virtual call into a direct call. The method_idx is into referrer's
           // dex cache, check that this resolved method is where we expect it.
-          CHECK(referrer_class->GetDexCache()->GetResolvedMethod(method_idx) == resolved_method)
-              << PrettyMethod(resolved_method);
-          stats_->VirtualMadeDirect(type);
-          GetCodeAndMethodForDirectCall(type, kDirect, referrer_class, resolved_method,
-                                        direct_code, direct_method);
-          type = kDirect;
+          CHECK(referrer_class->GetDexCache()->GetResolvedMethod(target_method.dex_method_index) ==
+                resolved_method) << PrettyMethod(resolved_method);
+          if (update_stats) {
+            stats_->ResolvedMethod(invoke_type);
+            stats_->VirtualMadeDirect(invoke_type);
+          }
+          GetCodeAndMethodForDirectCall(invoke_type, kDirect, referrer_class, resolved_method,
+                                        direct_code, direct_method, update_stats);
+          invoke_type = kDirect;
           return true;
-        } else if(can_devirtualize && kEnableSharpening && kEnableVerifierBasedSharpening) {
-            // If traditional sharpening fails, try the sharpening based on type information (Devirtualization)
-            mirror::DexCache* dex_cache = mUnit->GetClassLinker()->FindDexCache(*ref_sharpen->first);
-            mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader());
-            mirror::AbstractMethod* concrete_method = mUnit->GetClassLinker()->ResolveMethod(
-                *ref_sharpen->first, ref_sharpen->second, dex_cache, class_loader, NULL, kVirtual);
-            CHECK(concrete_method != NULL);
-            CHECK(!concrete_method->IsAbstract());
-            // TODO: fix breakage in image patching to be able to devirtualize cases with different
-            // resolved and concrete methods.
-            if(resolved_method == concrete_method) {
-              GetCodeAndMethodForDirectCall(type, kDirect, referrer_class, concrete_method, direct_code, direct_method);
-              stats_->VirtualMadeDirect(type);
-              type = kDirect;
-              stats_->PreciseTypeDevirtualization();
-            }
-            stats_->ResolvedMethod(type);
-            return true;
         }
-        else if (type == kSuper) {
+        const bool kEnableVerifierBasedSharpening = true;
+        if (kEnableVerifierBasedSharpening && (invoke_type == kVirtual ||
+                                               invoke_type == kInterface)) {
+          // Did the verifier record a more precise invoke target based on its type information?
+          const CompilerDriver::MethodReference caller_method(mUnit->GetDexFile(),
+                                                              mUnit->GetDexMethodIndex());
+          const CompilerDriver::MethodReference* devirt_map_target =
+              verifier::MethodVerifier::GetDevirtMap(caller_method, dex_pc);
+          if (devirt_map_target != NULL) {
+            mirror::DexCache* target_dex_cache =
+                mUnit->GetClassLinker()->FindDexCache(*devirt_map_target->dex_file);
+            mirror::ClassLoader* class_loader =
+                soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader());
+            mirror::AbstractMethod* called_method =
+                mUnit->GetClassLinker()->ResolveMethod(*devirt_map_target->dex_file,
+                                                       devirt_map_target->dex_method_index,
+                                                       target_dex_cache, class_loader, NULL,
+                                                       kVirtual);
+            CHECK(called_method != NULL);
+            CHECK(!called_method->IsAbstract());
+            GetCodeAndMethodForDirectCall(invoke_type, kDirect, referrer_class, called_method,
+                                          direct_code, direct_method, update_stats);
+            bool compiler_needs_dex_cache =
+                (GetCompilerBackend() == kPortable) ||
+                (GetCompilerBackend() == kQuick && instruction_set_ != kThumb2) ||
+                (direct_code == 0) || (direct_code == static_cast<unsigned int>(-1)) ||
+                (direct_method == 0) || (direct_method == static_cast<unsigned int>(-1));
+            if ((devirt_map_target->dex_file != target_method.dex_file) &&
+                compiler_needs_dex_cache) {
+              // We need to use the dex cache to find either the method or code, and the dex file
+              // containing the method isn't the one expected for the target method. Try to find
+              // the method within the expected target dex file.
+              // TODO: the -1 could be handled as direct code if the patching new the target dex
+              //       file.
+              // TODO: quick only supports direct pointers with Thumb2.
+              // TODO: the following should be factored into a common helper routine to find
+              //       one dex file's method within another.
+              const DexFile* dexfile = target_method.dex_file;
+              const DexFile* cm_dexfile =
+                  called_method->GetDeclaringClass()->GetDexCache()->GetDexFile();
+              const DexFile::MethodId& cm_method_id =
+                  cm_dexfile->GetMethodId(called_method->GetDexMethodIndex());
+              const char* cm_descriptor = cm_dexfile->StringByTypeIdx(cm_method_id.class_idx_);
+              const DexFile::StringId* descriptor = dexfile->FindStringId(cm_descriptor);
+              if (descriptor != NULL) {
+                const DexFile::TypeId* type_id =
+                    dexfile->FindTypeId(dexfile->GetIndexForStringId(*descriptor));
+                if (type_id != NULL) {
+                  const char* cm_name = cm_dexfile->GetMethodName(cm_method_id);
+                  const DexFile::StringId* name = dexfile->FindStringId(cm_name);
+                  if (name != NULL) {
+                    uint16_t return_type_idx;
+                    std::vector<uint16_t> param_type_idxs;
+                    bool success = dexfile->CreateTypeList(&return_type_idx, &param_type_idxs,
+                                                           cm_dexfile->GetMethodSignature(cm_method_id));
+                    if (success) {
+                      const DexFile::ProtoId* sig =
+                          dexfile->FindProtoId(return_type_idx, param_type_idxs);
+                      if (sig != NULL) {
+                        const  DexFile::MethodId* method_id = dexfile->FindMethodId(*type_id,
+                                                                                    *name, *sig);
+                        if (method_id != NULL) {
+                          if (update_stats) {
+                            stats_->ResolvedMethod(invoke_type);
+                            stats_->VirtualMadeDirect(invoke_type);
+                            stats_->PreciseTypeDevirtualization();
+                          }
+                          target_method.dex_method_index = dexfile->GetIndexForMethodId(*method_id);
+                          invoke_type = kDirect;
+                          return true;
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+              // TODO: the stats for direct code and method are off as we failed to find the direct
+              //       method in the referring method's dex cache/file.
+            } else {
+              if (update_stats) {
+                stats_->ResolvedMethod(invoke_type);
+                stats_->VirtualMadeDirect(invoke_type);
+                stats_->PreciseTypeDevirtualization();
+              }
+              target_method = *devirt_map_target;
+              invoke_type = kDirect;
+              return true;
+            }
+          }
+        }
+        if (invoke_type == kSuper) {
           // Unsharpened super calls are suspicious so go slow-path.
         } else {
-          stats_->ResolvedMethod(type);
-          GetCodeAndMethodForDirectCall(type, type, referrer_class, resolved_method,
-                                        direct_code, direct_method);
+          // Sharpening failed so generate a regular resolved method dispatch.
+          if (update_stats) {
+            stats_->ResolvedMethod(invoke_type);
+          }
+          if (invoke_type == kVirtual || invoke_type == kSuper) {
+            vtable_idx = resolved_method->GetMethodIndex();
+          }
+          GetCodeAndMethodForDirectCall(invoke_type, invoke_type, referrer_class, resolved_method,
+                                        direct_code, direct_method, update_stats);
           return true;
         }
       }
     }
   }
-  // Clean up any exception left by method/type resolution
+  // Clean up any exception left by method/invoke_type resolution
   if (soa.Self()->IsExceptionPending()) {
       soa.Self()->ClearException();
   }
-  stats_->UnresolvedMethod(type);
+  if (update_stats) {
+    stats_->UnresolvedMethod(invoke_type);
+  }
   return false;  // Incomplete knowledge needs slow path.
 }
 
+bool CompilerDriver::IsSafeCast(const MethodReference& mr, uint32_t dex_pc) {
+  bool result = verifier::MethodVerifier::IsSafeCast(mr, dex_pc);
+  if (result) {
+    stats_->SafeCast();
+  } else {
+    stats_->NotASafeCast();
+  }
+  return result;
+}
+
+
 void CompilerDriver::AddCodePatch(const DexFile* dex_file,
                             uint32_t referrer_method_idx,
                             InvokeType referrer_invoke_type,
@@ -1404,10 +1796,13 @@
   "Ljava/io/ObjectStreamClass;",  // Calls to Class.forName -> java.io.FileDescriptor.
   "Ljava/io/ObjectStreamConstants;", // Instance of non-image class SerializablePermission.
   "Ljava/lang/ClassLoader$SystemClassLoader;", // Calls System.getProperty -> OsConstants.initConstants.
+  "Ljava/lang/HexStringParser;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
+  "Ljava/lang/ProcessManager;", // Calls Thread.currentThread.
   "Ljava/lang/Runtime;", // Calls System.getProperty -> OsConstants.initConstants.
   "Ljava/lang/System;", // Calls OsConstants.initConstants.
   "Ljava/math/BigDecimal;", // Calls native ... -> java.math.NativeBN.BN_new().
   "Ljava/math/BigInteger;", // Calls native ... -> java.math.NativeBN.BN_new().
+  "Ljava/math/Primality;", // Calls native ... -> java.math.NativeBN.BN_new().
   "Ljava/math/Multiplication;", // Calls native ... -> java.math.NativeBN.BN_new().
   "Ljava/net/InetAddress;", // Requires libcore.io.OsConstants.
   "Ljava/net/Inet4Address;", // Sub-class of InetAddress.
@@ -1416,23 +1811,57 @@
   "Ljava/nio/charset/Charset;", // Calls Charset.getDefaultCharset -> System.getProperty -> OsConstants.initConstants.
   "Ljava/nio/charset/CharsetICU;", // Sub-class of Charset.
   "Ljava/nio/charset/Charsets;", // Calls Charset.forName.
+  "Ljava/security/AlgorithmParameterGenerator;", // Calls OsConstants.initConstants.
+  "Ljava/security/KeyPairGenerator$KeyPairGeneratorImpl;", // Calls OsConstants.initConstants.
   "Ljava/security/KeyPairGenerator;", // Calls OsConstants.initConstants.
   "Ljava/security/Security;", // Tries to do disk IO for "security.properties".
+  "Ljava/security/spec/RSAKeyGenParameterSpec;", // java.math.NativeBN.BN_new()
   "Ljava/sql/Date;", // Calls OsConstants.initConstants.
+  "Ljava/sql/DriverManager;", // Calls OsConstants.initConstants.
+  "Ljava/sql/Time;", // Calls OsConstants.initConstants.
+  "Ljava/sql/Timestamp;", // Calls OsConstants.initConstants.
   "Ljava/util/Date;", // Calls Date.<init> -> System.currentTimeMillis -> OsConstants.initConstants.
+  "Ljava/util/ListResourceBundle;", // Calls OsConstants.initConstants.
   "Ljava/util/Locale;", // Calls System.getProperty -> OsConstants.initConstants.
+  "Ljava/util/PropertyResourceBundle;", // Calls OsConstants.initConstants.
+  "Ljava/util/ResourceBundle;", // Calls OsConstants.initConstants.
+  "Ljava/util/ResourceBundle$MissingBundle;", // Calls OsConstants.initConstants.
+  "Ljava/util/Scanner;", // regex.Pattern.compileImpl.
   "Ljava/util/SimpleTimeZone;", // Sub-class of TimeZone.
   "Ljava/util/TimeZone;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
   "Ljava/util/concurrent/ConcurrentHashMap$Segment;", // Calls Runtime.getRuntime().availableProcessors().
+  "Ljava/util/concurrent/ConcurrentSkipListMap;", // Calls OsConstants.initConstants.
+  "Ljava/util/concurrent/Exchanger;", // Calls OsConstants.initConstants.
+  "Ljava/util/concurrent/ForkJoinPool;", // Calls OsConstants.initConstants.
+  "Ljava/util/concurrent/LinkedTransferQueue;", // Calls OsConstants.initConstants.
+  "Ljava/util/concurrent/Phaser;", // Calls OsConstants.initConstants.
+  "Ljava/util/concurrent/ScheduledThreadPoolExecutor;", // Calls AtomicLong.VMSupportsCS8()
+  "Ljava/util/concurrent/SynchronousQueue;", // Calls OsConstants.initConstants.
+  "Ljava/util/concurrent/atomic/AtomicLong;", // Calls AtomicLong.VMSupportsCS8()
   "Ljava/util/logging/LogManager;", // Calls System.getProperty -> OsConstants.initConstants.
+  "Ljava/util/prefs/AbstractPreferences;", // Calls OsConstants.initConstants.
+  "Ljava/util/prefs/FilePreferencesImpl;", // Calls OsConstants.initConstants.
+  "Ljava/util/prefs/FilePreferencesFactoryImpl;", // Calls OsConstants.initConstants.
+  "Ljava/util/prefs/Preferences;", // Calls OsConstants.initConstants.
+  "Ljavax/crypto/KeyAgreement;", // Calls OsConstants.initConstants.
+  "Ljavax/crypto/KeyGenerator;", // Calls OsConstants.initConstants.
+  "Ljavax/security/cert/X509Certificate;", // Calls VMClassLoader.getBootClassPathSize.
+  "Ljavax/security/cert/X509Certificate$1;", // Calls VMClassLoader.getBootClassPathSize.
   "Ljavax/microedition/khronos/egl/EGL10;", // Requires EGLContext.
   "Ljavax/microedition/khronos/egl/EGLContext;", // Requires com.google.android.gles_jni.EGLImpl.
   "Ljavax/net/ssl/HttpsURLConnection;", // Calls SSLSocketFactory.getDefault -> java.security.Security.getProperty.
+  "Ljavax/xml/datatype/DatatypeConstants;", // Calls OsConstants.initConstants.
+  "Ljavax/xml/datatype/FactoryFinder;", // Calls OsConstants.initConstants.
+  "Ljavax/xml/namespace/QName;", // Calls OsConstants.initConstants.
+  "Ljavax/xml/validation/SchemaFactoryFinder;", // Calls OsConstants.initConstants.
+  "Ljavax/xml/xpath/XPathConstants;", // Calls OsConstants.initConstants.
+  "Ljavax/xml/xpath/XPathFactoryFinder;", // Calls OsConstants.initConstants.
   "Llibcore/icu/LocaleData;", // Requires java.util.Locale.
   "Llibcore/icu/TimeZoneNames;", // Requires java.util.TimeZone.
   "Llibcore/io/IoUtils;",  // Calls Random.<init> -> System.currentTimeMillis -> FileDescriptor -> OsConstants.initConstants.
   "Llibcore/io/OsConstants;", // Platform specific.
   "Llibcore/net/MimeUtils;", // Calls libcore.net.MimeUtils.getContentTypesPropertiesStream -> System.getProperty.
+  "Llibcore/reflect/Types;", // Calls OsConstants.initConstants.
   "Llibcore/util/ZoneInfo;", // Sub-class of TimeZone.
   "Llibcore/util/ZoneInfoDB;", // Calls System.getenv -> OsConstants.initConstants.
   "Lorg/apache/commons/logging/LogFactory;", // Calls System.getProperty.
@@ -1440,17 +1869,40 @@
   "Lorg/apache/harmony/security/provider/cert/X509CertFactoryImpl;", // Requires java.nio.charsets.Charsets.
   "Lorg/apache/harmony/security/provider/crypto/RandomBitsSupplier;", // Requires java.io.File.
   "Lorg/apache/harmony/security/utils/AlgNameMapper;", // Requires java.util.Locale.
+  "Lorg/apache/harmony/security/pkcs10/CertificationRequest;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/pkcs10/CertificationRequestInfo;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/pkcs7/AuthenticatedAttributes;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/pkcs7/SignedData;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/pkcs7/SignerInfo;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/pkcs8/PrivateKeyInfo;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl;", // Calls OsConstants.initConstants.
   "Lorg/apache/harmony/security/x501/AttributeTypeAndValue;", // Calls IntegralToString.convertInt -> Thread.currentThread.
   "Lorg/apache/harmony/security/x501/DirectoryString;", // Requires BigInteger.
   "Lorg/apache/harmony/security/x501/Name;", // Requires org.apache.harmony.security.x501.AttributeTypeAndValue.
+  "Lorg/apache/harmony/security/x509/AccessDescription;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/AuthorityKeyIdentifier;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/CRLDistributionPoints;", // Calls Thread.currentThread.
   "Lorg/apache/harmony/security/x509/Certificate;", // Requires org.apache.harmony.security.x509.TBSCertificate.
-  "Lorg/apache/harmony/security/x509/TBSCertificate;",  // Requires org.apache.harmony.security.x501.Name.
+  "Lorg/apache/harmony/security/x509/CertificateIssuer;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/CertificateList;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/DistributionPoint;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/DistributionPointName;", // Calls Thread.currentThread.
   "Lorg/apache/harmony/security/x509/EDIPartyName;", // Calls native ... -> java.math.NativeBN.BN_new().
   "Lorg/apache/harmony/security/x509/GeneralName;", // Requires org.apache.harmony.security.x501.Name.
   "Lorg/apache/harmony/security/x509/GeneralNames;", // Requires GeneralName.
+  "Lorg/apache/harmony/security/x509/GeneralSubtree;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/GeneralSubtrees;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/InfoAccessSyntax;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/IssuingDistributionPoint;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/NameConstraints;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/TBSCertList$RevokedCertificate;", // Calls NativeBN.BN_new().
+  "Lorg/apache/harmony/security/x509/TBSCertList;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/TBSCertificate;",  // Requires org.apache.harmony.security.x501.Name.
   "Lorg/apache/harmony/security/x509/Time;", // Calls native ... -> java.math.NativeBN.BN_new().
   "Lorg/apache/harmony/security/x509/Validity;", // Requires x509.Time.
+  "Lorg/apache/harmony/security/x509/tsp/TSTInfo;", // Calls Thread.currentThread.
   "Lorg/apache/harmony/xml/ExpatParser;", // Calls native ExpatParser.staticInitialize.
+  "Lorg/apache/harmony/xml/ExpatParser$EntityParser;", // Calls ExpatParser.staticInitialize.
   "Lorg/apache/http/conn/params/ConnRouteParams;", // Requires java.util.Locale.
   "Lorg/apache/http/conn/ssl/SSLSocketFactory;", // Calls java.security.Security.getProperty.
   "Lorg/apache/http/conn/util/InetAddressUtils;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
@@ -1480,6 +1932,9 @@
     // Only try to initialize classes that were successfully verified.
     if (klass->IsVerified()) {
       manager->GetClassLinker()->EnsureInitialized(klass, false, can_init_static_fields);
+      if (soa.Self()->IsExceptionPending()) {
+        soa.Self()->GetException(NULL)->Dump();
+      }
       if (!klass->IsInitialized()) {
         if (can_init_static_fields) {
           bool is_black_listed = false;
@@ -1517,7 +1972,7 @@
       compiled_class = new CompiledClass(status);
       manager->GetCompiler()->RecordClassStatus(ref, compiled_class);
     } else {
-      DCHECK_EQ(status, compiled_class->GetStatus());
+      DCHECK_GE(status, compiled_class->GetStatus()) << descriptor;
     }
   }
   // Clear any class not found or verification exceptions.
@@ -1641,7 +2096,8 @@
   } else if ((access_flags & kAccAbstract) != 0) {
   } else {
     // In small mode we only compile image classes.
-    bool dont_compile = Runtime::Current()->IsSmallMode() && ((image_classes_ == NULL) || (image_classes_->size() == 0));
+    bool dont_compile = (Runtime::Current()->IsSmallMode() &&
+                         ((image_classes_.get() == NULL) || (image_classes_->size() == 0)));
 
     // Don't compile class initializers, ever.
     if (((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) {
diff --git a/src/compiler/driver/compiler_driver.h b/src/compiler/driver/compiler_driver.h
index 75d276d..fbfcadb 100644
--- a/src/compiler/driver/compiler_driver.h
+++ b/src/compiler/driver/compiler_driver.h
@@ -39,7 +39,6 @@
 class DexCompilationUnit;
 class TimingLogger;
 
-const uint32_t kDexPCNotReady = 0xFFFFFF;
 enum CompilerBackend {
   kQuick,
   kPortable,
@@ -62,14 +61,16 @@
 
 class CompilerDriver {
  public:
+  typedef std::set<std::string> DescriptorSet;
+
   // Create a compiler targeting the requested "instruction_set".
   // "image" should be true if image specific optimizations should be
   // enabled.  "image_classes" lets the compiler know what classes it
   // can assume will be in the image, with NULL implying all available
   // classes.
-  explicit CompilerDriver(CompilerBackend compiler_backend, InstructionSet instruction_set, bool image,
+  explicit CompilerDriver(CompilerBackend compiler_backend, InstructionSet instruction_set,
+                          bool image, DescriptorSet* image_classes,
                           size_t thread_count, bool support_debugging,
-                          const std::set<std::string>* image_classes, 
                           bool dump_stats, bool dump_timings);
 
   ~CompilerDriver();
@@ -97,8 +98,22 @@
     return image_;
   }
 
+  DescriptorSet* GetImageClasses() const {
+    return image_classes_.get();
+  }
+
   CompilerTls* GetTls();
 
+  // Generate the trampolines that are invoked by unresolved direct methods.
+  const std::vector<uint8_t>* CreatePortableResolutionTrampoline() const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const std::vector<uint8_t>* CreateQuickResolutionTrampoline() const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const std::vector<uint8_t>* CreateInterpreterToQuickEntry() const
+      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;
 
@@ -106,7 +121,22 @@
       LOCKS_EXCLUDED(compiled_classes_lock_);
 
   // A method is uniquely located by its DexFile and the method_ids_ table index into that DexFile
-  typedef std::pair<const DexFile*, uint32_t> MethodReference;
+  struct MethodReference {
+    MethodReference(const DexFile* file, uint32_t index) : dex_file(file), dex_method_index(index) {
+    }
+    const DexFile* dex_file;
+    uint32_t dex_method_index;
+  };
+
+  struct MethodReferenceComparator {
+    bool operator()(MethodReference mr1, MethodReference mr2) const {
+      if (mr1.dex_file == mr2.dex_file) {
+        return mr1.dex_method_index < mr2.dex_method_index;
+      } else {
+        return mr1.dex_file < mr2.dex_file;
+      }
+    }
+  };
 
   CompiledMethod* GetCompiledMethod(MethodReference ref) const
       LOCKS_EXCLUDED(compiled_methods_lock_);
@@ -124,7 +154,9 @@
 
   // Are runtime access checks necessary in the compiled code?
   bool CanAccessTypeWithoutChecks(uint32_t referrer_idx, const DexFile& dex_file,
-                                  uint32_t type_idx)
+                                  uint32_t type_idx, bool* type_known_final = NULL,
+                                  bool* type_known_abstract = NULL,
+                                  bool* equals_referrers_class = NULL)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
   // Are runtime access and instantiable checks necessary in the code?
@@ -146,11 +178,13 @@
 
   // Can we fastpath a interface, super class or virtual method call? Computes method's vtable
   // index.
-  bool ComputeInvokeInfo(uint32_t method_idx, uint32_t dex_pc,
-                         const DexCompilationUnit* mUnit, InvokeType& type, int& vtable_idx,
-                         uintptr_t& direct_code, uintptr_t& direct_method)
+  bool ComputeInvokeInfo(const DexCompilationUnit* mUnit, const uint32_t dex_pc,
+                         InvokeType& type, MethodReference& target_method, int& vtable_idx,
+                         uintptr_t& direct_code, uintptr_t& direct_method, bool update_stats)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
+  bool IsSafeCast(const MethodReference& mr, uint32_t dex_pc);
+
   // Record patch information for later fix up.
   void AddCodePatch(const DexFile* dex_file,
                     uint32_t referrer_method_idx,
@@ -169,6 +203,15 @@
 
   void SetBitcodeFileName(std::string const& filename);
 
+  bool GetSupportBootImageFixup() const {
+    return support_boot_image_fixup_;
+  }
+
+  void SetSupportBootImageFixup(bool support_boot_image_fixup) {
+    support_boot_image_fixup_ = support_boot_image_fixup;
+  }
+
+
   // TODO: remove these Elf wrappers when libart links against LLVM (when separate compiler library is gone)
   bool WriteElf(const std::string& android_root,
                 bool is_host,
@@ -253,7 +296,7 @@
   }
 
   // Checks if class specified by type_idx is one of the image_classes_
-  bool IsImageClass(const std::string& descriptor) const;
+  bool IsImageClass(const char* descriptor) const;
 
   void RecordClassStatus(ClassReference ref, CompiledClass* compiled_class);
 
@@ -262,13 +305,16 @@
   void GetCodeAndMethodForDirectCall(InvokeType type, InvokeType sharp_type,
                                      mirror::Class* referrer_class,
                                      mirror::AbstractMethod* method,
-                                     uintptr_t& direct_code, uintptr_t& direct_method)
+                                     uintptr_t& direct_code, uintptr_t& direct_method,
+                                     bool update_stats)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
                   ThreadPool& thread_pool, TimingLogger& timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
+  void LoadImageClasses(TimingLogger& timings);
+
   // Attempt to resolve all type, methods, fields, and strings
   // referenced from code in the dex file following PathClassLoader
   // ordering semantics.
@@ -292,6 +338,10 @@
                          ThreadPool& thread_pool, TimingLogger& timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_, compiled_classes_lock_);
 
+  void UpdateImageClasses(TimingLogger& timings);
+  static void FindClinitImageClassesCallback(mirror::Object* object, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   void Compile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
                ThreadPool& thread_pool, TimingLogger& timings);
   void CompileDexFile(jobject class_loader, const DexFile& dex_file,
@@ -321,12 +371,18 @@
   mutable Mutex compiled_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   ClassTable compiled_classes_ GUARDED_BY(compiled_classes_lock_);
 
-  typedef SafeMap<const MethodReference, CompiledMethod*> MethodTable;
+  typedef SafeMap<const MethodReference, CompiledMethod*, MethodReferenceComparator> MethodTable;
   // All method references that this compiler has compiled.
   mutable Mutex compiled_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   MethodTable compiled_methods_ GUARDED_BY(compiled_methods_lock_);
 
-  bool image_;
+  const bool image_;
+
+  // If image_ is true, specifies the classes that will be included in
+  // the image. Note if image_classes_ is NULL, all classes are
+  // included in the image.
+  UniquePtr<DescriptorSet> image_classes_;
+
   size_t thread_count_;
   bool support_debugging_;
   uint64_t start_ns_;
@@ -336,8 +392,6 @@
   bool dump_stats_;
   bool dump_timings_;
 
-  const std::set<std::string>* image_classes_;
-
   typedef void (*CompilerCallbackFn)(CompilerDriver& driver);
   typedef MutexLock* (*CompilerMutexLockFn)(CompilerDriver& driver);
 
@@ -366,6 +420,8 @@
       (const CompilerDriver& driver, const CompiledMethod* cm, const mirror::AbstractMethod* method);
   CompilerGetMethodCodeAddrFn compiler_get_method_code_addr_;
 
+  bool support_boot_image_fixup_;
+
   DISALLOW_COPY_AND_ASSIGN(CompilerDriver);
 };
 
diff --git a/src/compiler/driver/compiler_driver_test.cc b/src/compiler/driver/compiler_driver_test.cc
index c87fefd..a7fad6f 100644
--- a/src/compiler/driver/compiler_driver_test.cc
+++ b/src/compiler/driver/compiler_driver_test.cc
@@ -26,7 +26,7 @@
 #include "heap.h"
 #include "mirror/class.h"
 #include "mirror/class-inl.h"
-#include "mirror/dex_cache.h"
+#include "mirror/dex_cache-inl.h"
 #include "mirror/abstract_method-inl.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/object-inl.h"
diff --git a/src/compiler/driver/dex_compilation_unit.cc b/src/compiler/driver/dex_compilation_unit.cc
index 962df42..c7a4df6 100644
--- a/src/compiler/driver/dex_compilation_unit.cc
+++ b/src/compiler/driver/dex_compilation_unit.cc
@@ -31,18 +31,17 @@
       code_item_(cu->code_item),
       class_def_idx_(cu->class_def_idx),
       dex_method_idx_(cu->method_idx),
-      access_flags_(cu->access_flags),
-      symbol_(StringPrintf("dex_%s", MangleForJni(PrettyMethod(dex_method_idx_, *dex_file_)).c_str())) {
+      access_flags_(cu->access_flags) {
 }
 
-DexCompilationUnit:: DexCompilationUnit(CompilationUnit* cu,
-                                        jobject class_loader,
-                                        ClassLinker* class_linker,
-                                        const DexFile& dex_file,
-                                        const DexFile::CodeItem* code_item,
-                                        uint32_t class_def_idx,
-                                        uint32_t method_idx,
-                                        uint32_t access_flags)
+DexCompilationUnit::DexCompilationUnit(CompilationUnit* cu,
+                                       jobject class_loader,
+                                       ClassLinker* class_linker,
+                                       const DexFile& dex_file,
+                                       const DexFile::CodeItem* code_item,
+                                       uint32_t class_def_idx,
+                                       uint32_t method_idx,
+                                       uint32_t access_flags)
     : cu_(cu),
       class_loader_(class_loader),
       class_linker_(class_linker),
@@ -50,8 +49,15 @@
       code_item_(code_item),
       class_def_idx_(class_def_idx),
       dex_method_idx_(method_idx),
-      access_flags_(access_flags),
-      symbol_(StringPrintf("dex_%s", MangleForJni(PrettyMethod(dex_method_idx_, *dex_file_)).c_str())) {
+      access_flags_(access_flags) {
+}
+
+const std::string& DexCompilationUnit::GetSymbol() {
+  if (symbol_.empty()) {
+    symbol_ = "dex_";
+    symbol_ += MangleForJni(PrettyMethod(dex_method_idx_, *dex_file_));
+  }
+  return symbol_;
 }
 
 } // namespace art
diff --git a/src/compiler/driver/dex_compilation_unit.h b/src/compiler/driver/dex_compilation_unit.h
index 0b90aaa..3c6129d 100644
--- a/src/compiler/driver/dex_compilation_unit.h
+++ b/src/compiler/driver/dex_compilation_unit.h
@@ -92,9 +92,7 @@
     return ((access_flags_ & kAccSynchronized) != 0);
   }
 
-  const std::string& GetSymbol() const {
-    return symbol_;
-  }
+  const std::string& GetSymbol();
 
  private:
   CompilationUnit* const cu_;
@@ -110,7 +108,7 @@
   const uint32_t dex_method_idx_;
   const uint32_t access_flags_;
 
-  const std::string symbol_;
+  std::string symbol_;
 };
 
 } // namespace art
diff --git a/src/compiler/llvm/gbc_expander.cc b/src/compiler/llvm/gbc_expander.cc
index 99c8fd5..bdf9aca 100644
--- a/src/compiler/llvm/gbc_expander.cc
+++ b/src/compiler/llvm/gbc_expander.cc
@@ -776,7 +776,8 @@
   art::InvokeType invoke_type =
       static_cast<art::InvokeType>(LV2UInt(call_inst.getArgOperand(0)));
   bool is_static = (invoke_type == art::kStatic);
-  uint32_t callee_method_idx = LV2UInt(call_inst.getArgOperand(1));
+  art::CompilerDriver::MethodReference target_method(dex_compilation_unit_->GetDexFile(),
+                                                     LV2UInt(call_inst.getArgOperand(1)));
 
   // Load *this* actual parameter
   llvm::Value* this_addr = (!is_static) ? call_inst.getArgOperand(3) : NULL;
@@ -785,18 +786,17 @@
   int vtable_idx = -1;
   uintptr_t direct_code = 0;
   uintptr_t direct_method = 0;
-  // TODO: pass actual value of dex PC (instead of kDexPCNotready) needed by verifier based
-  // sharpening after LLVM re-factoring is finished.
-  bool is_fast_path = driver_->
-      ComputeInvokeInfo(callee_method_idx, art::kDexPCNotReady, dex_compilation_unit_,
-                        invoke_type, vtable_idx, direct_code, direct_method);
-
+  bool is_fast_path = driver_->ComputeInvokeInfo(dex_compilation_unit_, dex_pc,
+                                                 invoke_type, target_method,
+                                                 vtable_idx,
+                                                 direct_code, direct_method,
+                                                 true);
   // Load the method object
   llvm::Value* callee_method_object_addr = NULL;
 
   if (!is_fast_path) {
     callee_method_object_addr =
-        EmitCallRuntimeForCalleeMethodObjectAddr(callee_method_idx, invoke_type,
+        EmitCallRuntimeForCalleeMethodObjectAddr(target_method.dex_method_index, invoke_type,
                                                  this_addr, dex_pc, is_fast_path);
   } else {
     switch (invoke_type) {
@@ -809,7 +809,7 @@
                                   irb_.getJObjectTy());
         } else {
           callee_method_object_addr =
-              EmitLoadSDCalleeMethodObjectAddr(callee_method_idx);
+              EmitLoadSDCalleeMethodObjectAddr(target_method.dex_method_index);
         }
         break;
 
@@ -826,7 +826,7 @@
 
       case art::kInterface:
         callee_method_object_addr =
-            EmitCallRuntimeForCalleeMethodObjectAddr(callee_method_idx,
+            EmitCallRuntimeForCalleeMethodObjectAddr(target_method.dex_method_index,
                                                      invoke_type, this_addr,
                                                      dex_pc, is_fast_path);
         break;
@@ -844,7 +844,7 @@
 
   llvm::Value* code_addr;
   llvm::Type* func_type = GetFunctionType(call_inst.getType(),
-                                          callee_method_idx, is_static);
+                                          target_method.dex_method_index, is_static);
   if (direct_code != 0u && direct_code != static_cast<uintptr_t>(-1)) {
     code_addr =
         irb_.CreateIntToPtr(irb_.getPtrEquivInt(direct_code),
diff --git a/src/compiler/llvm/llvm_compilation_unit.h b/src/compiler/llvm/llvm_compilation_unit.h
index d96e778..857d924 100644
--- a/src/compiler/llvm/llvm_compilation_unit.h
+++ b/src/compiler/llvm/llvm_compilation_unit.h
@@ -81,10 +81,10 @@
   void SetCompilerDriver(CompilerDriver* driver) {
     driver_ = driver;
   }
-  const DexCompilationUnit* GetDexCompilationUnit() {
+  DexCompilationUnit* GetDexCompilationUnit() {
     return dex_compilation_unit_;
   }
-  void SetDexCompilationUnit(const DexCompilationUnit* dex_compilation_unit) {
+  void SetDexCompilationUnit(DexCompilationUnit* dex_compilation_unit) {
     dex_compilation_unit_ = dex_compilation_unit;
   }
 
@@ -113,7 +113,7 @@
   UniquePtr<IntrinsicHelper> intrinsic_helper_;
   UniquePtr<LLVMInfo> llvm_info_;
   CompilerDriver* driver_;
-  const DexCompilationUnit* dex_compilation_unit_;
+  DexCompilationUnit* dex_compilation_unit_;
 
   std::string bitcode_filename_;
 
diff --git a/src/compiler/llvm/runtime_support_llvm.cc b/src/compiler/llvm/runtime_support_llvm.cc
index bd6b01b..f3cfb33 100644
--- a/src/compiler/llvm/runtime_support_llvm.cc
+++ b/src/compiler/llvm/runtime_support_llvm.cc
@@ -24,6 +24,7 @@
 #include "dex_instruction.h"
 #include "mirror/abstract_method-inl.h"
 #include "mirror/class-inl.h"
+#include "mirror/dex_cache-inl.h"
 #include "mirror/field-inl.h"
 #include "mirror/object.h"
 #include "mirror/object-inl.h"
@@ -435,7 +436,7 @@
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticPrimitiveWrite, sizeof(uint32_t));
+                            StaticPrimitiveWrite, sizeof(uint32_t), true);
   if (LIKELY(field != NULL)) {
     field->Set32(field->GetDeclaringClass(), new_value);
     return 0;
@@ -451,7 +452,7 @@
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticPrimitiveWrite, sizeof(uint64_t));
+                            StaticPrimitiveWrite, sizeof(uint64_t), true);
   if (LIKELY(field != NULL)) {
     field->Set64(field->GetDeclaringClass(), new_value);
     return 0;
@@ -467,7 +468,7 @@
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticObjectWrite, sizeof(mirror::Object*));
+                            StaticObjectWrite, sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     field->SetObj(field->GetDeclaringClass(), new_value);
     return 0;
@@ -482,7 +483,7 @@
     return field->Get32(field->GetDeclaringClass());
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticPrimitiveRead, sizeof(uint32_t));
+                            StaticPrimitiveRead, sizeof(uint32_t), true);
   if (LIKELY(field != NULL)) {
     return field->Get32(field->GetDeclaringClass());
   }
@@ -496,7 +497,7 @@
     return field->Get64(field->GetDeclaringClass());
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticPrimitiveRead, sizeof(uint64_t));
+                            StaticPrimitiveRead, sizeof(uint64_t), true);
   if (LIKELY(field != NULL)) {
     return field->Get64(field->GetDeclaringClass());
   }
@@ -510,7 +511,7 @@
     return field->GetObj(field->GetDeclaringClass());
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticObjectRead, sizeof(mirror::Object*));
+                            StaticObjectRead, sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     return field->GetObj(field->GetDeclaringClass());
   }
@@ -526,7 +527,7 @@
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstancePrimitiveWrite, sizeof(uint32_t));
+                            InstancePrimitiveWrite, sizeof(uint32_t), true);
   if (LIKELY(field != NULL)) {
     field->Set32(obj, new_value);
     return 0;
@@ -543,7 +544,7 @@
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstancePrimitiveWrite, sizeof(uint64_t));
+                            InstancePrimitiveWrite, sizeof(uint64_t), true);
   if (LIKELY(field != NULL)) {
     field->Set64(obj, new_value);
     return 0;
@@ -560,7 +561,7 @@
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstanceObjectWrite, sizeof(mirror::Object*));
+                            InstanceObjectWrite, sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     field->SetObj(obj, new_value);
     return 0;
@@ -575,7 +576,7 @@
     return field->Get32(obj);
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstancePrimitiveRead, sizeof(uint32_t));
+                            InstancePrimitiveRead, sizeof(uint32_t), true);
   if (LIKELY(field != NULL)) {
     return field->Get32(obj);
   }
@@ -589,7 +590,7 @@
     return field->Get64(obj);
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstancePrimitiveRead, sizeof(uint64_t));
+                            InstancePrimitiveRead, sizeof(uint64_t), true);
   if (LIKELY(field != NULL)) {
     return field->Get64(obj);
   }
@@ -603,7 +604,7 @@
     return field->GetObj(obj);
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstanceObjectRead, sizeof(mirror::Object*));
+                            InstanceObjectRead, sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     return field->GetObj(obj);
   }
diff --git a/src/compiler/stubs/portable/stubs.cc b/src/compiler/stubs/portable/stubs.cc
new file mode 100644
index 0000000..db551bf
--- /dev/null
+++ b/src/compiler/stubs/portable/stubs.cc
@@ -0,0 +1,136 @@
+/*
+ * 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 "compiler/stubs/stubs.h"
+#include "jni_internal.h"
+#include "oat/utils/arm/assembler_arm.h"
+#include "oat/utils/mips/assembler_mips.h"
+#include "oat/utils/x86/assembler_x86.h"
+#include "oat/runtime/oat_support_entrypoints.h"
+#include "stack_indirect_reference_table.h"
+#include "sirt_ref.h"
+
+#define __ assembler->
+
+namespace art {
+
+namespace arm {
+const std::vector<uint8_t>* CreatePortableResolutionTrampoline() {
+  UniquePtr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm)));
+  RegList save = (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3) | (1 << LR);
+
+  __ PushList(save);
+  __ LoadFromOffset(kLoadWord, R12, TR, ENTRYPOINT_OFFSET(pPortableResolutionTrampolineFromCode));
+  __ mov(R3, ShifterOperand(TR));  // Pass Thread::Current() in R3
+  __ mov(R2, ShifterOperand(SP));  // Pass sp for Method** callee_addr
+  __ IncreaseFrameSize(12);         // 3 words of space for alignment
+  // Call to resolution trampoline (callee, receiver, callee_addr, Thread*)
+  __ blx(R12);
+  __ mov(R12, ShifterOperand(R0));  // Save code address returned into R12
+  __ DecreaseFrameSize(12);
+  __ PopList(save);
+  __ cmp(R12, ShifterOperand(0));
+  __ bx(R12, NE);                   // If R12 != 0 tail call method's code
+  __ bx(LR);                        // Return to caller to handle exception
+
+  assembler->EmitSlowPaths();
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > resolution_trampoline(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*resolution_trampoline)[0], resolution_trampoline->size());
+  assembler->FinalizeInstructions(code);
+
+  return resolution_trampoline.release();
+}
+} // namespace arm
+
+namespace mips {
+const std::vector<uint8_t>* CreatePortableResolutionTrampoline() {
+  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, 12);
+  __ StoreToOffset(kStoreWord, A2, SP, 8);
+  __ StoreToOffset(kStoreWord, A1, SP, 4);
+  __ StoreToOffset(kStoreWord, A0, SP, 0);
+
+  __ LoadFromOffset(kLoadWord, T9, S1,
+                    ENTRYPOINT_OFFSET(pPortableResolutionTrampolineFromCode));
+  __ Move(A3, S1);  // Pass Thread::Current() in A3
+  __ Move(A2, SP);  // Pass SP for Method** callee_addr
+  __ Jalr(T9); // Call to resolution trampoline (callee, receiver, callee_addr, Thread*)
+
+  // Restore frame, argument registers, and RA.
+  __ LoadFromOffset(kLoadWord, A0, SP, 0);
+  __ LoadFromOffset(kLoadWord, A1, SP, 4);
+  __ LoadFromOffset(kLoadWord, A2, SP, 8);
+  __ LoadFromOffset(kLoadWord, A3, SP, 12);
+  __ LoadFromOffset(kLoadWord, RA, SP, 28);
+  __ AddConstant(SP, SP, 32);
+
+  Label resolve_fail;
+  __ EmitBranch(V0, ZERO, &resolve_fail, true);
+  __ Jr(V0); // If V0 != 0 tail call method's code
+  __ Bind(&resolve_fail, false);
+  __ Jr(RA); // Return to caller to handle exception
+
+  assembler->EmitSlowPaths();
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > resolution_trampoline(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*resolution_trampoline)[0], resolution_trampoline->size());
+  assembler->FinalizeInstructions(code);
+
+  return resolution_trampoline.release();
+}
+} // namespace mips
+
+namespace x86 {
+const std::vector<uint8_t>* CreatePortableResolutionTrampoline() {
+  UniquePtr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
+
+  __ pushl(EBP);
+  __ movl(EBP, ESP);          // save ESP
+  __ subl(ESP, Immediate(8));  // Align stack
+  __ movl(EAX, Address(EBP, 8));  // Method* called
+  __ leal(EDX, Address(EBP, 8));  // Method** called_addr
+  __ fs()->pushl(Address::Absolute(Thread::SelfOffset()));  // pass thread
+  __ pushl(EDX);  // pass called_addr
+  __ pushl(ECX);  // pass receiver
+  __ pushl(EAX);  // pass called
+  // Call to resolve method.
+  __ Call(ThreadOffset(ENTRYPOINT_OFFSET(pPortableResolutionTrampolineFromCode)),
+          X86ManagedRegister::FromCpuRegister(ECX));
+  __ leave();
+
+  Label resolve_fail;  // forward declaration
+  __ cmpl(EAX, Immediate(0));
+  __ j(kEqual, &resolve_fail);
+  __ jmp(EAX);
+  // Tail call to intended method.
+  __ Bind(&resolve_fail);
+  __ ret();
+
+  assembler->EmitSlowPaths();
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > resolution_trampoline(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*resolution_trampoline)[0], resolution_trampoline->size());
+  assembler->FinalizeInstructions(code);
+
+  return resolution_trampoline.release();
+}
+} // namespace x86
+
+} // namespace art
diff --git a/src/compiler/stubs/quick/stubs.cc b/src/compiler/stubs/quick/stubs.cc
new file mode 100644
index 0000000..a8e691f
--- /dev/null
+++ b/src/compiler/stubs/quick/stubs.cc
@@ -0,0 +1,262 @@
+/*
+ * 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 "compiler/stubs/stubs.h"
+#include "jni_internal.h"
+#include "oat/utils/arm/assembler_arm.h"
+#include "oat/utils/mips/assembler_mips.h"
+#include "oat/utils/x86/assembler_x86.h"
+#include "oat/runtime/oat_support_entrypoints.h"
+#include "stack_indirect_reference_table.h"
+#include "sirt_ref.h"
+
+#define __ assembler->
+
+namespace art {
+
+namespace arm {
+const std::vector<uint8_t>* CreateQuickResolutionTrampoline() {
+  UniquePtr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm)));
+  // | Out args |
+  // | Method*  | <- SP on entry
+  // | LR       |    return address into caller
+  // | ...      |    callee saves
+  // | R3       |    possible argument
+  // | R2       |    possible argument
+  // | R1       |    possible argument
+  // | R0       |    junk on call to QuickResolutionTrampolineFromCode, holds result Method*
+  // | Method*  |    Callee save Method* set up by QuickResoltuionTrampolineFromCode
+  // Save callee saves and ready frame for exception delivery
+  RegList save = (1 << R1) | (1 << R2) | (1 << R3) | (1 << R5) | (1 << R6) | (1 << R7) | (1 << R8) |
+                 (1 << R10) | (1 << R11) | (1 << LR);
+  // TODO: enable when GetCalleeSaveMethod is available at stub generation time
+  // DCHECK_EQ(save, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetCoreSpillMask());
+  __ PushList(save);
+  __ LoadFromOffset(kLoadWord, R12, TR, ENTRYPOINT_OFFSET(pQuickResolutionTrampolineFromCode));
+  __ mov(R3, ShifterOperand(TR));  // Pass Thread::Current() in R3
+  __ IncreaseFrameSize(8);         // 2 words of space for alignment
+  __ mov(R2, ShifterOperand(SP));  // Pass SP
+  // Call to resolution trampoline (method_idx, receiver, sp, Thread*)
+  __ blx(R12);
+  __ mov(R12, ShifterOperand(R0));  // Save code address returned into R12
+  // Restore registers which may have been modified by GC, "R0" will hold the Method*
+  __ DecreaseFrameSize(4);
+  __ PopList((1 << R0) | save);
+  __ bx(R12);  // Leaf call to method's code
+  __ bkpt(0);
+
+  assembler->EmitSlowPaths();
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > resolution_trampoline(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*resolution_trampoline)[0], resolution_trampoline->size());
+  assembler->FinalizeInstructions(code);
+
+  return resolution_trampoline.release();
+}
+
+const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() {
+  UniquePtr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm)));
+
+  __ LoadFromOffset(kLoadWord, PC, R0, ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry));
+  __ bkpt(0);
+
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
+  assembler->FinalizeInstructions(code);
+
+  return entry_stub.release();
+}
+
+const std::vector<uint8_t>* CreateInterpreterToQuickEntry() {
+  UniquePtr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm)));
+
+  __ LoadFromOffset(kLoadWord, PC, R0, ENTRYPOINT_OFFSET(pInterpreterToQuickEntry));
+  __ bkpt(0);
+
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
+  assembler->FinalizeInstructions(code);
+
+  return entry_stub.release();
+}
+} // namespace arm
+
+namespace mips {
+const std::vector<uint8_t>* CreateQuickResolutionTrampoline() {
+  UniquePtr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
+  // | Out args   |
+  // | Method*    | <- SP on entry
+  // | RA         |    return address into caller
+  // | ...        |    callee saves
+  // | A3         |    possible argument
+  // | A2         |    possible argument
+  // | A1         |    possible argument
+  // | A0/Method* |    Callee save Method* set up by UnresolvedDirectMethodTrampolineFromCode
+  // 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, GP, SP, 52);
+  __ StoreToOffset(kStoreWord, S7, SP, 48);
+  __ StoreToOffset(kStoreWord, S6, SP, 44);
+  __ StoreToOffset(kStoreWord, S5, SP, 40);
+  __ StoreToOffset(kStoreWord, S4, SP, 36);
+  __ StoreToOffset(kStoreWord, S3, SP, 32);
+  __ StoreToOffset(kStoreWord, S2, SP, 28);
+  __ StoreToOffset(kStoreWord, A3, SP, 12);
+  __ StoreToOffset(kStoreWord, A2, SP, 8);
+  __ StoreToOffset(kStoreWord, A1, SP, 4);
+
+  __ LoadFromOffset(kLoadWord, T9, S1, ENTRYPOINT_OFFSET(pQuickResolutionTrampolineFromCode));
+  __ Move(A3, S1);  // Pass Thread::Current() in A3
+  __ Move(A2, SP);  // Pass SP for Method** callee_addr
+  __ Jalr(T9); // Call to resolution trampoline (method_idx, receiver, sp, Thread*)
+
+  // Restore registers which may have been modified by GC
+  __ LoadFromOffset(kLoadWord, A0, SP, 0);
+  __ LoadFromOffset(kLoadWord, A1, SP, 4);
+  __ LoadFromOffset(kLoadWord, A2, SP, 8);
+  __ LoadFromOffset(kLoadWord, A3, SP, 12);
+  __ LoadFromOffset(kLoadWord, S2, SP, 28);
+  __ LoadFromOffset(kLoadWord, S3, SP, 32);
+  __ LoadFromOffset(kLoadWord, S4, SP, 36);
+  __ LoadFromOffset(kLoadWord, S5, SP, 40);
+  __ LoadFromOffset(kLoadWord, S6, SP, 44);
+  __ LoadFromOffset(kLoadWord, S7, SP, 48);
+  __ LoadFromOffset(kLoadWord, GP, SP, 52);
+  __ LoadFromOffset(kLoadWord, FP, SP, 56);
+  __ LoadFromOffset(kLoadWord, RA, SP, 60);
+  __ AddConstant(SP, SP, 64);
+
+  __ Move(T9, V0); // Put method's code in T9
+  __ Jr(T9);  // Leaf call to method's code
+
+  __ Break();
+
+  assembler->EmitSlowPaths();
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > resolution_trampoline(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*resolution_trampoline)[0], resolution_trampoline->size());
+  assembler->FinalizeInstructions(code);
+
+  return resolution_trampoline.release();
+}
+
+const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() {
+  UniquePtr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
+
+  __ LoadFromOffset(kLoadWord, T9, A0, ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry));
+  __ Jr(T9);
+  __ Break();
+
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
+  assembler->FinalizeInstructions(code);
+
+  return entry_stub.release();
+}
+
+const std::vector<uint8_t>* CreateInterpreterToQuickEntry() {
+  UniquePtr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
+
+  __ LoadFromOffset(kLoadWord, T9, A0, ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry));
+  __ Jr(T9);
+  __ Break();
+
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
+  assembler->FinalizeInstructions(code);
+
+  return entry_stub.release();
+}
+} // namespace mips
+
+namespace x86 {
+const std::vector<uint8_t>* CreateQuickResolutionTrampoline() {
+  UniquePtr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
+  // Set up the callee save frame to conform with Runtime::CreateCalleeSaveMethod(kRefsAndArgs)
+  // return address
+  __ pushl(EDI);
+  __ pushl(ESI);
+  __ pushl(EBP);
+  __ pushl(EBX);
+  __ pushl(EDX);
+  __ pushl(ECX);
+  __ pushl(EAX);  // <-- callee save Method* to go here
+  __ movl(EDX, ESP);          // save ESP
+  __ fs()->pushl(Address::Absolute(Thread::SelfOffset()));  // pass Thread*
+  __ pushl(EDX);              // pass ESP for Method*
+  __ pushl(ECX);              // pass receiver
+  __ pushl(EAX);              // pass Method*
+
+  // Call to resolve method.
+  __ Call(ThreadOffset(ENTRYPOINT_OFFSET(pQuickResolutionTrampolineFromCode)),
+          X86ManagedRegister::FromCpuRegister(ECX));
+
+  __ movl(EDI, EAX);  // save code pointer in EDI
+  __ addl(ESP, Immediate(16));  // Pop arguments
+  __ popl(EAX);  // Restore args.
+  __ popl(ECX);
+  __ popl(EDX);
+  __ popl(EBX);
+  __ popl(EBP);  // Restore callee saves.
+  __ popl(ESI);
+  // Swap EDI callee save with code pointer
+  __ xchgl(EDI, Address(ESP, 0));
+  // Tail call to intended method.
+  __ ret();
+
+  assembler->EmitSlowPaths();
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > resolution_trampoline(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*resolution_trampoline)[0], resolution_trampoline->size());
+  assembler->FinalizeInstructions(code);
+
+  return resolution_trampoline.release();
+}
+
+const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() {
+  UniquePtr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
+
+  __ fs()->jmp(Address::Absolute(ThreadOffset(ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry))));
+
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
+  assembler->FinalizeInstructions(code);
+
+  return entry_stub.release();
+}
+
+const std::vector<uint8_t>* CreateInterpreterToQuickEntry() {
+  UniquePtr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
+
+  __ fs()->jmp(Address::Absolute(ThreadOffset(ENTRYPOINT_OFFSET(pInterpreterToQuickEntry))));
+
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
+  assembler->FinalizeInstructions(code);
+
+  return entry_stub.release();
+}
+} // namespace x86
+
+} // namespace art
diff --git a/src/compiler/stubs/stubs.h b/src/compiler/stubs/stubs.h
new file mode 100644
index 0000000..ebe761d
--- /dev/null
+++ b/src/compiler/stubs/stubs.h
@@ -0,0 +1,59 @@
+/*
+ * 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_COMPILER_STUBS_STUBS_H_
+#define ART_SRC_COMPILER_STUBS_STUBS_H_
+
+#include "runtime.h"
+
+namespace art {
+
+namespace arm {
+const std::vector<uint8_t>* CreatePortableResolutionTrampoline()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateQuickResolutionTrampoline()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateInterpreterToQuickEntry()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+}
+
+namespace mips {
+const std::vector<uint8_t>* CreatePortableResolutionTrampoline()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateQuickResolutionTrampoline()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateInterpreterToQuickEntry()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+}
+
+namespace x86 {
+const std::vector<uint8_t>* CreatePortableResolutionTrampoline()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateQuickResolutionTrampoline()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateInterpreterToQuickEntry()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+}
+
+}  // namespace art
+
+#endif  // ART_SRC_COMPILER_STUBS_STUBS_H_
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index ad751d0..f678ee9 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -161,18 +161,15 @@
   }
 
 
-  // Make a list of descriptors for classes to include in the image
-  std::set<std::string>* GetImageClassDescriptors(const char* image_classes_filename)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  // Reads the class names (java.lang.Object) and returns as set of class descriptors (Ljava/lang/Object;)
+  CompilerDriver::DescriptorSet* ReadImageClasses(const char* image_classes_filename) {
     UniquePtr<std::ifstream> image_classes_file(new std::ifstream(image_classes_filename, std::ifstream::in));
     if (image_classes_file.get() == NULL) {
       LOG(ERROR) << "Failed to open image classes file " << image_classes_filename;
       return NULL;
     }
 
-    // Load all the classes specified in the file
-    ClassLinker* class_linker = runtime_->GetClassLinker();
-    Thread* self = Thread::Current();
+    UniquePtr<CompilerDriver::DescriptorSet> image_classes(new CompilerDriver::DescriptorSet);
     while (image_classes_file->good()) {
       std::string dot;
       std::getline(*image_classes_file.get(), dot);
@@ -180,51 +177,9 @@
         continue;
       }
       std::string descriptor(DotToDescriptor(dot.c_str()));
-      SirtRef<mirror::Class> klass(self, class_linker->FindSystemClass(descriptor.c_str()));
-      if (klass.get() == NULL) {
-        LOG(WARNING) << "Failed to find class " << descriptor;
-        Thread::Current()->ClearException();
-      }
+      image_classes->insert(descriptor);
     }
     image_classes_file->close();
-
-    // Resolve exception classes referenced by the loaded classes. The catch logic assumes
-    // exceptions are resolved by the verifier when there is a catch block in an interested method.
-    // Do this here so that exception classes appear to have been specified image classes.
-    std::set<std::pair<uint16_t, const DexFile*> > unresolved_exception_types;
-    SirtRef<mirror::Class> java_lang_Throwable(self,
-                                       class_linker->FindSystemClass("Ljava/lang/Throwable;"));
-    do {
-      unresolved_exception_types.clear();
-      class_linker->VisitClasses(ResolveCatchBlockExceptionsClassVisitor,
-                                 &unresolved_exception_types);
-      typedef std::set<std::pair<uint16_t, const DexFile*> >::const_iterator It;  // TODO: C++0x auto
-      for (It it = unresolved_exception_types.begin(),
-           end = unresolved_exception_types.end();
-           it != end; ++it) {
-        uint16_t exception_type_idx = it->first;
-        const DexFile* dex_file = it->second;
-        mirror::DexCache* dex_cache = class_linker->FindDexCache(*dex_file);
-        mirror:: ClassLoader* class_loader = NULL;
-        SirtRef<mirror::Class> klass(self, class_linker->ResolveType(*dex_file, exception_type_idx,
-                                                                     dex_cache, class_loader));
-        if (klass.get() == NULL) {
-          const DexFile::TypeId& type_id = dex_file->GetTypeId(exception_type_idx);
-          const char* descriptor = dex_file->GetTypeDescriptor(type_id);
-          LOG(FATAL) << "Failed to resolve class " << descriptor;
-        }
-        DCHECK(java_lang_Throwable->IsAssignableFrom(klass.get()));
-      }
-      // Resolving exceptions may load classes that reference more exceptions, iterate until no
-      // more are found
-    } while (!unresolved_exception_types.empty());
-
-    // We walk the roots looking for classes so that we'll pick up the
-    // above classes plus any classes them depend on such super
-    // classes, interfaces, and the required ClassLinker roots.
-    UniquePtr<ImageWriter::DescriptorSet> image_classes(new ImageWriter::DescriptorSet);
-    class_linker->VisitClasses(RecordImageClassesVisitor, image_classes.get());
-    CHECK_NE(image_classes->size(), 0U);
     return image_classes.release();
   }
 
@@ -236,7 +191,7 @@
                                       File* oat_file,
                                       const std::string& bitcode_filename,
                                       bool image,
-                                      const ImageWriter::DescriptorSet* image_classes,
+                                      UniquePtr<CompilerDriver::DescriptorSet>& image_classes,
                                       bool dump_stats,
                                       bool dump_timings)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -260,9 +215,9 @@
     UniquePtr<CompilerDriver> driver(new CompilerDriver(compiler_backend_,
                                                         instruction_set_,
                                                         image,
+                                                        image_classes.release(),
                                                         thread_count_,
                                                         support_debugging_,
-                                                        image_classes,
                                                         dump_stats,
                                                         dump_timings));
 
@@ -280,11 +235,11 @@
     std::string image_file_location;
     uint32_t image_file_location_oat_checksum = 0;
     uint32_t image_file_location_oat_data_begin = 0;
-    Heap* heap = Runtime::Current()->GetHeap();
-    if (heap->GetSpaces().size() > 1) {
-      ImageSpace* image_space = heap->GetImageSpace();
+    if (!driver->IsImage()) {
+      ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace();
       image_file_location_oat_checksum = image_space->GetImageHeader().GetOatChecksum();
-      image_file_location_oat_data_begin = reinterpret_cast<uint32_t>(image_space->GetImageHeader().GetOatDataBegin());
+      image_file_location_oat_data_begin =
+          reinterpret_cast<uint32_t>(image_space->GetImageHeader().GetOatDataBegin());
       image_file_location = image_space->GetImageFilename();
       if (host_prefix != NULL && StartsWith(image_file_location, host_prefix->c_str())) {
         image_file_location = image_file_location.substr(host_prefix->size());
@@ -292,6 +247,13 @@
     }
 
     std::vector<uint8_t> oat_contents;
+    // TODO: change ElfWriterQuick to not require the creation of oat_contents. The old pre-mclinker
+    //       OatWriter streamed directly to disk. The new could can be adapted to do it as follows:
+    // 1.) use first pass of OatWriter to calculate size of oat structure,
+    // 2.) call ElfWriterQuick with pointer to OatWriter instead of contents,
+    // 3.) have ElfWriterQuick call back to OatWriter to stream generate the output directly in
+    //     place in the elf file.
+    oat_contents.reserve(5 * MB);
     VectorOutputStream vector_output_stream(oat_file->GetPath(), oat_contents);
     if (!OatWriter::Create(vector_output_stream,
                            dex_files,
@@ -313,7 +275,6 @@
 
   bool CreateImageFile(const std::string& image_filename,
                        uintptr_t image_base,
-                       ImageWriter::DescriptorSet* image_classes,
                        const std::string& oat_filename,
                        const std::string& oat_location,
                        const CompilerDriver& compiler)
@@ -321,8 +282,8 @@
     uintptr_t oat_data_begin;
     {
       // ImageWriter is scoped so it can free memory before doing FixupElf
-      ImageWriter image_writer(image_classes);
-      if (!image_writer.Write(image_filename, image_base, oat_filename, oat_location, compiler)) {
+      ImageWriter image_writer(compiler);
+      if (!image_writer.Write(image_filename, image_base, oat_filename, oat_location)) {
         LOG(ERROR) << "Failed to create image file " << image_filename;
         return false;
       }
@@ -373,72 +334,6 @@
     return true;
   }
 
-  static void ResolveExceptionsForMethod(MethodHelper* mh,
-                           std::set<std::pair<uint16_t, const DexFile*> >& exceptions_to_resolve)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    const DexFile::CodeItem* code_item = mh->GetCodeItem();
-    if (code_item == NULL) {
-      return;  // native or abstract method
-    }
-    if (code_item->tries_size_ == 0) {
-      return;  // nothing to process
-    }
-    const byte* encoded_catch_handler_list = DexFile::GetCatchHandlerData(*code_item, 0);
-    size_t num_encoded_catch_handlers = DecodeUnsignedLeb128(&encoded_catch_handler_list);
-    for (size_t i = 0; i < num_encoded_catch_handlers; i++) {
-      int32_t encoded_catch_handler_size = DecodeSignedLeb128(&encoded_catch_handler_list);
-      bool has_catch_all = false;
-      if (encoded_catch_handler_size <= 0) {
-        encoded_catch_handler_size = -encoded_catch_handler_size;
-        has_catch_all = true;
-      }
-      for (int32_t j = 0; j < encoded_catch_handler_size; j++) {
-        uint16_t encoded_catch_handler_handlers_type_idx =
-            DecodeUnsignedLeb128(&encoded_catch_handler_list);
-        // Add to set of types to resolve if not already in the dex cache resolved types
-        if (!mh->IsResolvedTypeIdx(encoded_catch_handler_handlers_type_idx)) {
-          exceptions_to_resolve.insert(
-              std::pair<uint16_t, const DexFile*>(encoded_catch_handler_handlers_type_idx,
-                                                  &mh->GetDexFile()));
-        }
-        // ignore address associated with catch handler
-        DecodeUnsignedLeb128(&encoded_catch_handler_list);
-      }
-      if (has_catch_all) {
-        // ignore catch all address
-        DecodeUnsignedLeb128(&encoded_catch_handler_list);
-      }
-    }
-  }
-
-  static bool ResolveCatchBlockExceptionsClassVisitor(mirror::Class* c, void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    std::set<std::pair<uint16_t, const DexFile*> >* exceptions_to_resolve =
-        reinterpret_cast<std::set<std::pair<uint16_t, const DexFile*> >*>(arg);
-    MethodHelper mh;
-    for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
-      mirror::AbstractMethod* m = c->GetVirtualMethod(i);
-      mh.ChangeMethod(m);
-      ResolveExceptionsForMethod(&mh, *exceptions_to_resolve);
-    }
-    for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
-      mirror::AbstractMethod* m = c->GetDirectMethod(i);
-      mh.ChangeMethod(m);
-      ResolveExceptionsForMethod(&mh, *exceptions_to_resolve);
-    }
-    return true;
-  }
-
-  static bool RecordImageClassesVisitor(mirror::Class* klass, void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    ImageWriter::DescriptorSet* image_classes = reinterpret_cast<ImageWriter::DescriptorSet*>(arg);
-    if (klass->IsArrayClass() || klass->IsPrimitive()) {
-      return true;
-    }
-    image_classes->insert(ClassHelper(klass).GetDescriptor());
-    return true;
-  }
-
   // Appends to dex_files any elements of class_path that it doesn't already
   // contain. This will open those dex files as necessary.
   static void OpenClassPathFiles(const std::string& class_path, std::vector<const DexFile*>& dex_files) {
@@ -633,6 +528,8 @@
   pthread_attr_t attr_;
   pthread_t pthread_;
 };
+const unsigned int WatchDog::kWatchDogWarningSeconds;
+const unsigned int WatchDog::kWatchDogTimeoutSeconds;
 
 static int dex2oat(int argc, char** argv) {
   InitLogging(argv);
@@ -920,7 +817,7 @@
 #endif // ART_SMALL_MODE
 
   Dex2Oat* p_dex2oat;
-  if (!Dex2Oat::Create(&p_dex2oat, options, compiler_backend, instruction_set, thread_count, 
+  if (!Dex2Oat::Create(&p_dex2oat, options, compiler_backend, instruction_set, thread_count,
                        support_debugging)) {
     LOG(ERROR) << "Failed to create dex2oat";
     return EXIT_FAILURE;
@@ -934,9 +831,9 @@
   ScopedObjectAccess soa(Thread::Current());
 
   // If --image-classes was specified, calculate the full list of classes to include in the image
-  UniquePtr<ImageWriter::DescriptorSet> image_classes(NULL);
+  UniquePtr<CompilerDriver::DescriptorSet> image_classes(NULL);
   if (image_classes_filename != NULL) {
-    image_classes.reset(dex2oat->GetImageClassDescriptors(image_classes_filename));
+    image_classes.reset(dex2oat->ReadImageClasses(image_classes_filename));
     if (image_classes.get() == NULL) {
       LOG(ERROR) << "Failed to create list of image classes from " << image_classes_filename;
       return EXIT_FAILURE;
@@ -992,7 +889,7 @@
                                                                   oat_file.get(),
                                                                   bitcode_filename,
                                                                   image,
-                                                                  image_classes.get(),
+                                                                  image_classes,
                                                                   dump_stats,
                                                                   dump_timings));
 
@@ -1057,7 +954,6 @@
     Thread::Current()->TransitionFromRunnableToSuspended(kNative);
     bool image_creation_success = dex2oat->CreateImageFile(image_filename,
                                                            image_base,
-                                                           image_classes.get(),
                                                            oat_unstripped,
                                                            oat_location,
                                                            *compiler.get());
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 0f0bed4..dad083c 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -373,10 +373,10 @@
   const uint16_t class_idx = GetIndexForTypeId(declaring_klass);
   const uint32_t name_idx = GetIndexForStringId(name);
   const uint16_t type_idx = GetIndexForTypeId(type);
-  uint32_t lo = 0;
-  uint32_t hi = NumFieldIds() - 1;
+  int32_t lo = 0;
+  int32_t hi = NumFieldIds() - 1;
   while (hi >= lo) {
-    uint32_t mid = (hi + lo) / 2;
+    int32_t mid = (hi + lo) / 2;
     const DexFile::FieldId& field = GetFieldId(mid);
     if (class_idx > field.class_idx_) {
       lo = mid + 1;
@@ -408,10 +408,10 @@
   const uint16_t class_idx = GetIndexForTypeId(declaring_klass);
   const uint32_t name_idx = GetIndexForStringId(name);
   const uint16_t proto_idx = GetIndexForProtoId(signature);
-  uint32_t lo = 0;
-  uint32_t hi = NumMethodIds() - 1;
+  int32_t lo = 0;
+  int32_t hi = NumMethodIds() - 1;
   while (hi >= lo) {
-    uint32_t mid = (hi + lo) / 2;
+    int32_t mid = (hi + lo) / 2;
     const DexFile::MethodId& method = GetMethodId(mid);
     if (class_idx > method.class_idx_) {
       lo = mid + 1;
@@ -436,15 +436,35 @@
   return NULL;
 }
 
-const DexFile::StringId* DexFile::FindStringId(const std::string& string) const {
-  uint32_t lo = 0;
-  uint32_t hi = NumStringIds() - 1;
+const DexFile::StringId* DexFile::FindStringId(const char* string) const {
+  int32_t lo = 0;
+  int32_t hi = NumStringIds() - 1;
   while (hi >= lo) {
-    uint32_t mid = (hi + lo) / 2;
+    int32_t mid = (hi + lo) / 2;
     uint32_t length;
     const DexFile::StringId& str_id = GetStringId(mid);
     const char* str = GetStringDataAndLength(str_id, &length);
-    int compare = CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(string.c_str(), str);
+    int compare = CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(string, str);
+    if (compare > 0) {
+      lo = mid + 1;
+    } else if (compare < 0) {
+      hi = mid - 1;
+    } else {
+      return &str_id;
+    }
+  }
+  return NULL;
+}
+
+const DexFile::StringId* DexFile::FindStringId(const uint16_t* string) const {
+  int32_t lo = 0;
+  int32_t hi = NumStringIds() - 1;
+  while (hi >= lo) {
+    int32_t mid = (hi + lo) / 2;
+    uint32_t length;
+    const DexFile::StringId& str_id = GetStringId(mid);
+    const char* str = GetStringDataAndLength(str_id, &length);
+    int compare = CompareModifiedUtf8ToUtf16AsCodePointValues(str, string);
     if (compare > 0) {
       lo = mid + 1;
     } else if (compare < 0) {
@@ -457,10 +477,10 @@
 }
 
 const DexFile::TypeId* DexFile::FindTypeId(uint32_t string_idx) const {
-  uint32_t lo = 0;
-  uint32_t hi = NumTypeIds() - 1;
+  int32_t lo = 0;
+  int32_t hi = NumTypeIds() - 1;
   while (hi >= lo) {
-    uint32_t mid = (hi + lo) / 2;
+    int32_t mid = (hi + lo) / 2;
     const TypeId& type_id = GetTypeId(mid);
     if (string_idx > type_id.descriptor_idx_) {
       lo = mid + 1;
@@ -475,10 +495,10 @@
 
 const DexFile::ProtoId* DexFile::FindProtoId(uint16_t return_type_idx,
                                          const std::vector<uint16_t>& signature_type_idxs) const {
-  uint32_t lo = 0;
-  uint32_t hi = NumProtoIds() - 1;
+  int32_t lo = 0;
+  int32_t hi = NumProtoIds() - 1;
   while (hi >= lo) {
-    uint32_t mid = (hi + lo) / 2;
+    int32_t mid = (hi + lo) / 2;
     const DexFile::ProtoId& proto = GetProtoId(mid);
     int compare = return_type_idx - proto.return_type_idx_;
     if (compare == 0) {
@@ -544,7 +564,7 @@
         descriptor += c;
       } while (c != ';');
     }
-    const DexFile::StringId* string_id = FindStringId(descriptor);
+    const DexFile::StringId* string_id = FindStringId(descriptor.c_str());
     if (string_id == NULL) {
       return false;
     }
diff --git a/src/dex_file.h b/src/dex_file.h
index 6e34b57..ecc985f 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -436,8 +436,11 @@
     return StringDataAndLengthByIdx(idx, &unicode_length);
   }
 
-  // Looks up a string id for a given string
-  const StringId* FindStringId(const std::string& string) const;
+  // Looks up a string id for a given modified utf8 string.
+  const StringId* FindStringId(const char* string) const;
+
+  // Looks up a string id for a given utf16 string.
+  const StringId* FindStringId(const uint16_t* string) const;
 
   // Returns the number of type identifiers in the .dex file.
   size_t NumTypeIds() const {
@@ -974,7 +977,7 @@
   bool HasNext() const {
     return pos_ < EndOfVirtualMethodsPos();
   }
-  void Next() {
+  inline void Next() {
     pos_++;
     if (pos_ < EndOfStaticFieldsPos()) {
       last_idx_ = GetMemberIndex();
diff --git a/src/dex_file_verifier.cc b/src/dex_file_verifier.cc
index b1efcaa..6df4411 100644
--- a/src/dex_file_verifier.cc
+++ b/src/dex_file_verifier.cc
@@ -369,10 +369,12 @@
   }
 
   if (expect_code && code_offset == 0) {
-    LOG(ERROR) << StringPrintf("Unexpected zero value for class_data_item method code_off with access flags %x", access_flags);
+    LOG(ERROR)<< StringPrintf("Unexpected zero value for class_data_item method code_off"
+        " with access flags %x", access_flags);
     return false;
   } else if (!expect_code && code_offset != 0) {
-    LOG(ERROR) << StringPrintf("Unexpected non-zero value %x for class_data_item method code_off with access flags %x", code_offset, access_flags);
+    LOG(ERROR) << StringPrintf("Unexpected non-zero value %x for class_data_item method code_off"
+        " with access flags %x", code_offset, access_flags);
     return false;
   }
 
@@ -544,7 +546,8 @@
     }
 
     if (last_idx >= idx && i != 0) {
-      LOG(ERROR) << StringPrintf("Out-of-order annotation_element name_idx: %x then %x", last_idx, idx);
+      LOG(ERROR) << StringPrintf("Out-of-order annotation_element name_idx: %x then %x",
+          last_idx, idx);
       return false;
     }
 
@@ -651,7 +654,8 @@
   uint32_t last_addr = 0;
   while (try_items_size--) {
     if (try_items->start_addr_ < last_addr) {
-      LOG(ERROR) << StringPrintf("Out-of_order try_item with start_addr: %x", try_items->start_addr_);
+      LOG(ERROR) << StringPrintf("Out-of_order try_item with start_addr: %x",
+          try_items->start_addr_);
       return false;
     }
 
@@ -933,7 +937,8 @@
   last_idx = 0;
   for (uint32_t i = 0; i < method_count; i++) {
     if (last_idx >= method_item->method_idx_ && i != 0) {
-      LOG(ERROR) << StringPrintf("Out-of-order method_idx for annotation: %x then %x", last_idx, method_item->method_idx_);
+      LOG(ERROR) << StringPrintf("Out-of-order method_idx for annotation: %x then %x",
+          last_idx, method_item->method_idx_);
       return false;
     }
     last_idx = method_item->method_idx_;
@@ -944,14 +949,16 @@
   const DexFile::ParameterAnnotationsItem* parameter_item =
       reinterpret_cast<const DexFile::ParameterAnnotationsItem*>(method_item);
   uint32_t parameter_count = item->parameters_size_;
-  if (!CheckListSize(parameter_item, parameter_count, sizeof(DexFile::ParameterAnnotationsItem), "parameter_annotations list")) {
+  if (!CheckListSize(parameter_item, parameter_count, sizeof(DexFile::ParameterAnnotationsItem),
+      "parameter_annotations list")) {
     return false;
   }
 
   last_idx = 0;
   for (uint32_t i = 0; i < parameter_count; i++) {
     if (last_idx >= parameter_item->method_idx_ && i != 0) {
-      LOG(ERROR) << StringPrintf("Out-of-order method_idx for annotation: %x then %x", last_idx, parameter_item->method_idx_);
+      LOG(ERROR) << StringPrintf("Out-of-order method_idx for annotation: %x then %x",
+          last_idx, parameter_item->method_idx_);
       return false;
     }
     last_idx = parameter_item->method_idx_;
@@ -1051,7 +1058,8 @@
         uint32_t count = list->size_;
 
         if (!CheckPointerRange(list, list + 1, "annotation_set_ref_list") ||
-            !CheckListSize(item, count, sizeof(DexFile::AnnotationSetRefItem), "annotation_set_ref_list size")) {
+            !CheckListSize(item, count, sizeof(DexFile::AnnotationSetRefItem),
+                "annotation_set_ref_list size")) {
           return false;
         }
         ptr_ = reinterpret_cast<const byte*>(item + count);
@@ -1257,7 +1265,8 @@
           return false;
         }
         if (section_offset != header_->map_off_) {
-          LOG(ERROR) << StringPrintf("Map not at header-defined offset: %x, expected %x", section_offset, header_->map_off_);
+          LOG(ERROR) << StringPrintf("Map not at header-defined offset: %x, expected %x",
+              section_offset, header_->map_off_);
           return false;
         }
         ptr_ += sizeof(uint32_t) + (map->size_ * sizeof(DexFile::MapItem));
@@ -1297,7 +1306,8 @@
     return false;
   }
   if (it->second != type) {
-    LOG(ERROR) << StringPrintf("Unexpected data map entry @ %x; expected %x, found %x", offset, type, it->second);
+    LOG(ERROR) << StringPrintf("Unexpected data map entry @ %x; expected %x, found %x",
+        offset, type, it->second);
     return false;
   }
   return true;
@@ -1380,7 +1390,8 @@
   if (previous_item_ != NULL) {
     const DexFile::TypeId* prev_item = reinterpret_cast<const DexFile::TypeId*>(previous_item_);
     if (prev_item->descriptor_idx_ >= item->descriptor_idx_) {
-      LOG(ERROR) << StringPrintf("Out-of-order type_ids: %x then %x", prev_item->descriptor_idx_, item->descriptor_idx_);
+      LOG(ERROR) << StringPrintf("Out-of-order type_ids: %x then %x",
+          prev_item->descriptor_idx_, item->descriptor_idx_);
       return false;
     }
   }
@@ -1757,7 +1768,8 @@
       LOG(ERROR) << "Mismatched defining class for parameter_annotation";
       return false;
     }
-    if (!CheckOffsetToTypeMap(parameter_item->annotations_off_, DexFile::kDexTypeAnnotationSetRefList)) {
+    if (!CheckOffsetToTypeMap(parameter_item->annotations_off_,
+        DexFile::kDexTypeAnnotationSetRefList)) {
       return false;
     }
     parameter_item++;
diff --git a/src/dex_instruction-inl.h b/src/dex_instruction-inl.h
index 99dab12..b426e66 100644
--- a/src/dex_instruction-inl.h
+++ b/src/dex_instruction-inl.h
@@ -21,13 +21,6 @@
 
 namespace art {
 
-inline const Instruction* Instruction::Next_51l() const {
-  DCHECK_EQ(FormatOf(Opcode()), k51l);
-  size_t current_size_in_bytes = 5 * sizeof(uint16_t);
-  const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
-  return reinterpret_cast<const Instruction*>(ptr + current_size_in_bytes);
-}
-
 //------------------------------------------------------------------------------
 // VRegA
 //------------------------------------------------------------------------------
@@ -36,6 +29,11 @@
   return static_cast<int8_t>(InstAA());
 }
 
+inline uint8_t Instruction::VRegA_10x() const {
+  DCHECK_EQ(FormatOf(Opcode()), k10x);
+  return InstAA();
+}
+
 inline uint4_t Instruction::VRegA_11n() const {
   DCHECK_EQ(FormatOf(Opcode()), k11n);
   return InstA();
diff --git a/src/dex_instruction.cc b/src/dex_instruction.cc
index 1b7d3bb..b18b4d0 100644
--- a/src/dex_instruction.cc
+++ b/src/dex_instruction.cc
@@ -299,7 +299,7 @@
         case NEW_INSTANCE:
           if (file != NULL) {
             uint32_t type_idx = VRegB_21c();
-            os << opcode << " v" << VRegA_21c() << ", " << PrettyType(type_idx, *file)
+            os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyType(type_idx, *file)
                << " // type@" << type_idx;
             break;
           }  // else fall-through
@@ -312,7 +312,7 @@
         case SGET_SHORT:
           if (file != NULL) {
             uint32_t field_idx = VRegB_21c();
-            os << opcode << "  v" << VRegA_21c() << ", " << PrettyField(field_idx, *file, true)
+            os << opcode << "  v" << static_cast<int>(VRegA_21c()) << ", " << PrettyField(field_idx, *file, true)
                << " // field@" << field_idx;
             break;
           }  // else fall-through
@@ -325,7 +325,7 @@
         case SPUT_SHORT:
           if (file != NULL) {
             uint32_t field_idx = VRegB_21c();
-            os << opcode << " v" << VRegA_21c() << ", " << PrettyField(field_idx, *file, true)
+            os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyField(field_idx, *file, true)
                << " // field@" << field_idx;
             break;
           }  // else fall-through
@@ -350,7 +350,7 @@
         case IGET_SHORT:
           if (file != NULL) {
             uint32_t field_idx = VRegC_22c();
-            os << opcode << " v" << VRegA_22c() << ", v" << VRegB_22c() << ", "
+            os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
                << PrettyField(field_idx, *file, true) << " // field@" << field_idx;
             break;
           }  // else fall-through
@@ -363,21 +363,21 @@
         case IPUT_SHORT:
           if (file != NULL) {
             uint32_t field_idx = VRegC_22c();
-            os << opcode << " v" << VRegA_22c() << ", v" << VRegB_22c() << ", "
+            os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
                << PrettyField(field_idx, *file, true) << " // field@" << field_idx;
             break;
           }  // else fall-through
         case INSTANCE_OF:
           if (file != NULL) {
             uint32_t type_idx = VRegC_22c();
-            os << opcode << " v" << VRegA_22c() << ", v" << VRegB_22c() << ", "
+            os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
                << PrettyType(type_idx, *file) << " // type@" << type_idx;
             break;
           }
         case NEW_ARRAY:
           if (file != NULL) {
             uint32_t type_idx = VRegC_22c();
-            os << opcode << " v" << VRegA_22c() << ", v" << VRegB_22c() << ", "
+            os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
                << PrettyType(type_idx, *file) << " // type@" << type_idx;
             break;
           }  // else fall-through
diff --git a/src/dex_instruction.h b/src/dex_instruction.h
index 218acb6..adaada7 100644
--- a/src/dex_instruction.h
+++ b/src/dex_instruction.h
@@ -162,39 +162,45 @@
     }
   }
 
+  // Reads an instruction out of the stream at the specified address.
+  static const Instruction* At(const uint16_t* code) {
+    DCHECK(code != NULL);
+    return reinterpret_cast<const Instruction*>(code);
+  }
+
+  // Reads an instruction out of the stream from the current address plus an offset.
+  const Instruction* RelativeAt(int32_t offset) const {
+    return At(reinterpret_cast<const uint16_t*>(this) + offset);
+  }
+
   // Returns a pointer to the next instruction in the stream.
   const Instruction* Next() const {
-    size_t current_size_in_bytes = SizeInCodeUnits() * sizeof(uint16_t);
-    const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
-    return reinterpret_cast<const Instruction*>(ptr + current_size_in_bytes);
+    return RelativeAt(SizeInCodeUnits());
   }
 
   // Returns a pointer to the instruction after this 1xx instruction in the stream.
   const Instruction* Next_1xx() const {
     DCHECK(FormatOf(Opcode()) >= k10x && FormatOf(Opcode()) <= k10t);
-    size_t current_size_in_bytes = 1 * sizeof(uint16_t);
-    const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
-    return reinterpret_cast<const Instruction*>(ptr + current_size_in_bytes);
+    return RelativeAt(1);
   }
 
   // Returns a pointer to the instruction after this 2xx instruction in the stream.
   const Instruction* Next_2xx() const {
     DCHECK(FormatOf(Opcode()) >= k20t && FormatOf(Opcode()) <= k22c);
-    size_t current_size_in_bytes = 2 * sizeof(uint16_t);
-    const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
-    return reinterpret_cast<const Instruction*>(ptr + current_size_in_bytes);
+    return RelativeAt(2);
   }
 
   // Returns a pointer to the instruction after this 3xx instruction in the stream.
   const Instruction* Next_3xx() const {
     DCHECK(FormatOf(Opcode()) >= k32x && FormatOf(Opcode()) <= k3rc);
-    size_t current_size_in_bytes = 3 * sizeof(uint16_t);
-    const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
-    return reinterpret_cast<const Instruction*>(ptr + current_size_in_bytes);
+    return RelativeAt(3);
   }
 
   // Returns a pointer to the instruction after this 51l instruction in the stream.
-  const Instruction* Next_51l() const;
+  const Instruction* Next_51l() const {
+    DCHECK(FormatOf(Opcode()) == k51l);
+    return RelativeAt(5);
+  }
 
   // Returns the name of this instruction's opcode.
   const char* Name() const {
@@ -208,6 +214,7 @@
 
   // VRegA
   int8_t VRegA_10t() const;
+  uint8_t VRegA_10x() const;
   uint4_t VRegA_11n() const;
   uint8_t VRegA_11x() const;
   uint4_t VRegA_12x() const;
@@ -271,12 +278,6 @@
     return static_cast<Code>(opcode);
   }
 
-  // Reads an instruction out of the stream at the specified address.
-  static const Instruction* At(const uint16_t* code) {
-    CHECK(code != NULL);
-    return reinterpret_cast<const Instruction*>(code);
-  }
-
   // Returns the format of the given opcode.
   static Format FormatOf(Code opcode) {
     return kInstructionFormats[opcode];
diff --git a/src/disassembler_arm.cc b/src/disassembler_arm.cc
index 7e75600..172bef8 100644
--- a/src/disassembler_arm.cc
+++ b/src/disassembler_arm.cc
@@ -1223,7 +1223,7 @@
         args << Rt << ", [" << Rn << ", #" << imm5 << "]";
       }
     } else if (opcode1 >= 0x34 && opcode1 <= 0x37) {  // 1101xx
-      uint32_t imm8 = instr & 0xFF;
+      int8_t imm8 = instr & 0xFF;
       uint32_t cond = (instr >> 8) & 0xF;
       opcode << "b";
       DumpCond(opcode, cond);
@@ -1260,7 +1260,7 @@
           uint16_t imm5 = (instr >> 3) & 0x1F;
           ThumbRegister Rn(instr, 0);
           opcode << (op != 0 ? "cbnz" : "cbz");
-          uint32_t imm32 = (i << 7) | (imm5 << 1);
+          uint32_t imm32 = (i << 6) | (imm5 << 1);
           args << Rn << ", ";
           DumpBranchTarget(args, instr_ptr + 4, imm32);
           break;
diff --git a/src/gc/mark_sweep.cc b/src/gc/mark_sweep.cc
index 25b4b78..14d604a 100644
--- a/src/gc/mark_sweep.cc
+++ b/src/gc/mark_sweep.cc
@@ -422,7 +422,9 @@
     ++large_object_test_;
   }
   if (UNLIKELY(!large_objects->Test(obj))) {
-    if (!large_object_space->Contains(obj)) {
+    // TODO: mark may be called holding the JNI global references lock, Contains will hold the
+    // large object space lock causing a lock level violation. Bug: 9414652;
+    if (!kDebugLocking && !large_object_space->Contains(obj)) {
       LOG(ERROR) << "Tried to mark " << obj << " not contained by any spaces";
       LOG(ERROR) << "Attempting see if it's a bad root";
       VerifyRoots();
diff --git a/src/image_test.cc b/src/image_test.cc
index 8066a90..0769e21 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -43,27 +43,19 @@
   {
     std::vector<uint8_t> oat_contents;
     {
+      jobject class_loader = NULL;
+      ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+      compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath());
+
       ScopedObjectAccess soa(Thread::Current());
-      std::vector<const DexFile*> dex_files;
-      dex_files.push_back(java_lang_dex_file_);
-      dex_files.push_back(conscrypt_file_);
       VectorOutputStream output_stream(tmp_elf.GetFilename(), oat_contents);
-      bool success_oat = OatWriter::Create(output_stream, dex_files, 0, 0, "", *compiler_driver_.get());
+      bool success_oat = OatWriter::Create(output_stream, class_linker->GetBootClassPath(),
+                                           0, 0, "", *compiler_driver_.get());
       ASSERT_TRUE(success_oat);
 
-      // Force all system classes into memory
-      for (size_t dex_file_index = 0; dex_file_index < dex_files.size(); ++dex_file_index) {
-        const DexFile* dex_file = dex_files[dex_file_index];
-        for (size_t class_def_index = 0; class_def_index < dex_file->NumClassDefs(); ++class_def_index) {
-          const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
-          const char* descriptor = dex_file->GetClassDescriptor(class_def);
-          mirror::Class* klass = class_linker_->FindSystemClass(descriptor);
-          EXPECT_TRUE(klass != NULL) << descriptor;
-        }
-      }
       bool success_elf = compiler_driver_->WriteElf(GetTestAndroidRoot(),
                                                     !kIsTargetBuild,
-                                                    dex_files,
+                                                    class_linker->GetBootClassPath(),
                                                     oat_contents,
                                                     tmp_elf.GetFile());
       ASSERT_TRUE(success_elf);
@@ -76,10 +68,9 @@
   ScratchFile tmp_image;
   const uintptr_t requested_image_base = ART_BASE_ADDRESS;
   {
-    ImageWriter writer(NULL);
+    ImageWriter writer(*compiler_driver_.get());
     bool success_image = writer.Write(tmp_image.GetFilename(), requested_image_base,
-                                      tmp_oat->GetPath(), tmp_oat->GetPath(),
-                                      *compiler_driver_.get());
+                                      tmp_oat->GetPath(), tmp_oat->GetPath());
     ASSERT_TRUE(success_image);
     bool success_fixup = compiler_driver_->FixupElf(tmp_oat.get(), writer.GetOatDataBegin());
     ASSERT_TRUE(success_fixup);
@@ -101,6 +92,9 @@
     ASSERT_GE(sizeof(image_header) + space->Size(), static_cast<size_t>(file->GetLength()));
   }
 
+  ASSERT_TRUE(compiler_driver_->GetImageClasses() != NULL);
+  CompilerDriver::DescriptorSet image_classes(*compiler_driver_->GetImageClasses());
+
   // Need to delete the compiler since it has worker threads which are attached to runtime.
   compiler_driver_.reset();
 
@@ -148,7 +142,13 @@
     mirror::Class* klass = class_linker_->FindSystemClass(descriptor);
     EXPECT_TRUE(klass != NULL) << descriptor;
     EXPECT_LT(image_begin, reinterpret_cast<byte*>(klass)) << descriptor;
-    EXPECT_LT(reinterpret_cast<byte*>(klass), image_end) << descriptor;
+    if (image_classes.find(descriptor) != image_classes.end()) {
+      // image classes should be located before the end of the image.
+      EXPECT_LT(reinterpret_cast<byte*>(klass), image_end) << descriptor;
+    } else {
+      // non image classes should be in a space after the image.
+      EXPECT_GT(reinterpret_cast<byte*>(klass), image_end) << descriptor;
+    }
     EXPECT_EQ(*klass->GetRawLockWordAddress(), 0);  // address should have been removed from monitor
   }
 }
diff --git a/src/image_writer.cc b/src/image_writer.cc
index a989a4e..5a1ebbb 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -36,7 +36,7 @@
 #include "mirror/array-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
-#include "mirror/dex_cache.h"
+#include "mirror/dex_cache-inl.h"
 #include "mirror/field-inl.h"
 #include "mirror/abstract_method-inl.h"
 #include "mirror/object-inl.h"
@@ -57,8 +57,7 @@
 bool ImageWriter::Write(const std::string& image_filename,
                         uintptr_t image_begin,
                         const std::string& oat_filename,
-                        const std::string& oat_location,
-                        const CompilerDriver& compiler_driver) {
+                        const std::string& oat_location) {
   CHECK(!image_filename.empty());
 
   CHECK_NE(image_begin, 0U);
@@ -81,6 +80,10 @@
   }
   oat_file_ = OatFile::OpenWritable(oat_file.get(), oat_location);
   class_linker->RegisterOatFile(*oat_file_);
+  interpreter_to_interpreter_entry_offset_ = oat_file_->GetOatHeader().GetInterpreterToInterpreterEntryOffset();
+  interpreter_to_quick_entry_offset_ = oat_file_->GetOatHeader().GetInterpreterToQuickEntryOffset();
+  portable_resolution_trampoline_offset_ = oat_file_->GetOatHeader().GetPortableResolutionTrampolineOffset();
+  quick_resolution_trampoline_offset_ = oat_file_->GetOatHeader().GetQuickResolutionTrampolineOffset();
 
   {
     Thread::Current()->TransitionFromSuspendedToRunnable();
@@ -110,10 +113,10 @@
   Thread::Current()->TransitionFromSuspendedToRunnable();
   size_t oat_loaded_size = 0;
   size_t oat_data_offset = 0;
-  compiler_driver.GetOatElfInformation(oat_file.get(), oat_loaded_size, oat_data_offset);
+  compiler_driver_.GetOatElfInformation(oat_file.get(), oat_loaded_size, oat_data_offset);
   CalculateNewObjectOffsets(oat_loaded_size, oat_data_offset);
   CopyAndFixupObjects();
-  PatchOatCodeAndMethods(compiler_driver);
+  PatchOatCodeAndMethods();
   Thread::Current()->TransitionFromRunnableToSuspended(kNative);
 
   UniquePtr<File> image_file(OS::OpenFile(image_filename.c_str(), true));
@@ -168,13 +171,13 @@
     return;
   }
   String* string = obj->AsString();
-  std::string utf8_string(string->ToModifiedUtf8());
+  const uint16_t* utf16_string = string->GetCharArray()->GetData() + string->GetOffset();
   ImageWriter* writer = reinterpret_cast<ImageWriter*>(arg);
   typedef Set::const_iterator CacheIt;  // TODO: C++0x auto
   for (CacheIt it = writer->dex_caches_.begin(), end = writer->dex_caches_.end(); it != end; ++it) {
     DexCache* dex_cache = *it;
     const DexFile& dex_file = *dex_cache->GetDexFile();
-    const DexFile::StringId* string_id = dex_file.FindStringId(utf8_string);
+    const DexFile::StringId* string_id = dex_file.FindStringId(utf16_string);
     if (string_id != NULL) {
       // This string occurs in this dex file, assign the dex cache entry.
       uint32_t string_idx = dex_file.GetIndexForStringId(*string_id);
@@ -195,42 +198,21 @@
 }
 
 bool ImageWriter::IsImageClass(const Class* klass) {
-  if (image_classes_ == NULL) {
-    return true;
-  }
-  while (klass->IsArrayClass()) {
-    klass = klass->GetComponentType();
-  }
-  if (klass->IsPrimitive()) {
-    return true;
-  }
-  const std::string descriptor(ClassHelper(klass).GetDescriptor());
-  return image_classes_->find(descriptor) != image_classes_->end();
+  return compiler_driver_.IsImageClass(ClassHelper(klass).GetDescriptor());
 }
 
-
 struct NonImageClasses {
   ImageWriter* image_writer;
   std::set<std::string>* non_image_classes;
 };
 
 void ImageWriter::PruneNonImageClasses() {
-  if (image_classes_ == NULL) {
+  if (compiler_driver_.GetImageClasses() == NULL) {
     return;
   }
   Runtime* runtime = Runtime::Current();
   ClassLinker* class_linker = runtime->GetClassLinker();
 
-  // Update image_classes_ with classes for objects created by <clinit> methods.
-  Thread* self = Thread::Current();
-  const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter");
-  Heap* heap = Runtime::Current()->GetHeap();
-  // TODO: Image spaces only?
-  WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
-  heap->FlushAllocStack();
-  heap->GetLiveBitmap()->Walk(FindClinitImageClassesCallback, this);
-  self->EndAssertNoThreadSuspension(old_cause);
-
   // Make a list of classes we would like to prune.
   std::set<std::string> non_image_classes;
   NonImageClasses context;
@@ -271,28 +253,6 @@
   }
 }
 
-void ImageWriter::FindClinitImageClassesCallback(Object* object, void* arg) {
-  DCHECK(object != NULL);
-  DCHECK(arg != NULL);
-  ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg);
-  Class* klass = object->GetClass();
-  while (klass->IsArrayClass()) {
-    klass = klass->GetComponentType();
-  }
-  if (klass->IsPrimitive()) {
-    return;
-  }
-  while (!klass->IsObjectClass()) {
-    ClassHelper kh(klass);
-    const char* descriptor = kh.GetDescriptor();
-    std::pair<DescriptorSet::iterator, bool> result = image_writer->image_classes_->insert(descriptor);
-    if (result.second) {
-      LOG(INFO) << "Adding " << descriptor << " to image classes";
-    }
-    klass = klass->GetSuperClass();
-  }
-}
-
 bool ImageWriter::NonImageClassesVisitor(Class* klass, void* arg) {
   NonImageClasses* context = reinterpret_cast<NonImageClasses*>(arg);
   if (!context->image_writer->IsImageClass(klass)) {
@@ -303,7 +263,7 @@
 
 void ImageWriter::CheckNonImageClassesRemoved()
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  if (image_classes_ == NULL) {
+  if (compiler_driver_.GetImageClasses() == NULL) {
     return;
   }
 
@@ -332,8 +292,10 @@
 }
 
 void ImageWriter::DumpImageClasses() {
+  CompilerDriver::DescriptorSet* image_classes = compiler_driver_.GetImageClasses();
+  CHECK(image_classes != NULL);
   typedef std::set<std::string>::const_iterator It;  // TODO: C++0x auto
-  for (It it = image_classes_->begin(), end = image_classes_->end(); it != end; ++it) {
+  for (It it = image_classes->begin(), end = image_classes->end(); it != end; ++it) {
     LOG(INFO) << " " << *it;
   }
 }
@@ -512,17 +474,34 @@
   if (orig->IsAbstract()) {
     // Code for abstract methods is set to the abstract method error stub when we load the image.
     copy->SetEntryPointFromCompiledCode(NULL);
+    copy->SetEntryPointFromInterpreter(reinterpret_cast<EntryPointFromInterpreter*>
+                                       (GetOatAddress(interpreter_to_interpreter_entry_offset_)));
     return;
+  } else {
+    copy->SetEntryPointFromInterpreter(reinterpret_cast<EntryPointFromInterpreter*>
+                                       (GetOatAddress(interpreter_to_quick_entry_offset_)));
   }
 
   if (orig == Runtime::Current()->GetResolutionMethod()) {
-    // The resolution method's code is set to the resolution trampoline when we load the image.
-    copy->SetEntryPointFromCompiledCode(NULL);
+#if defined(ART_USE_PORTABLE_COMPILER)
+    copy->SetEntryPointFromCompiledCode(GetOatAddress(portable_resolution_trampoline_offset_));
+#else
+    copy->SetEntryPointFromCompiledCode(GetOatAddress(quick_resolution_trampoline_offset_));
+#endif
     return;
   }
 
-  // Non-abstract methods have code
-  copy->SetEntryPointFromCompiledCode(GetOatAddress(orig->GetOatCodeOffset()));
+  // Use original code if it exists. Otherwise, set the code pointer to the resolution trampoline.
+  const byte* code = GetOatAddress(orig->GetOatCodeOffset());
+  if (code != NULL) {
+    copy->SetEntryPointFromCompiledCode(code);
+  } else {
+#if defined(ART_USE_PORTABLE_COMPILER)
+    copy->SetEntryPointFromCompiledCode(GetOatAddress(portable_resolution_trampoline_offset_));
+#else
+    copy->SetEntryPointFromCompiledCode(GetOatAddress(quick_resolution_trampoline_offset_));
+#endif
+  }
 
   if (orig->IsNative()) {
     // The native method's pointer is set to a stub to lookup via dlsym when we load the image.
@@ -638,13 +617,13 @@
   return method;
 }
 
-void ImageWriter::PatchOatCodeAndMethods(const CompilerDriver& compiler) {
+void ImageWriter::PatchOatCodeAndMethods() {
   Thread* self = Thread::Current();
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter");
 
   typedef std::vector<const CompilerDriver::PatchInformation*> Patches;
-  const Patches& code_to_patch = compiler.GetCodeToPatch();
+  const Patches& code_to_patch = compiler_driver_.GetCodeToPatch();
   for (size_t i = 0; i < code_to_patch.size(); i++) {
     const CompilerDriver::PatchInformation* patch = code_to_patch[i];
     AbstractMethod* target = GetTargetMethod(patch);
@@ -654,7 +633,7 @@
     SetPatchLocation(patch, reinterpret_cast<uint32_t>(GetOatAddress(code_offset)));
   }
 
-  const Patches& methods_to_patch = compiler.GetMethodsToPatch();
+  const Patches& methods_to_patch = compiler_driver_.GetMethodsToPatch();
   for (size_t i = 0; i < methods_to_patch.size(); i++) {
     const CompilerDriver::PatchInformation* patch = methods_to_patch[i];
     AbstractMethod* target = GetTargetMethod(patch);
diff --git a/src/image_writer.h b/src/image_writer.h
index 30a7f7f..4507592 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -37,18 +37,18 @@
 // Write a Space built during compilation for use during execution.
 class ImageWriter {
  public:
-  typedef std::set<std::string> DescriptorSet;
-  explicit ImageWriter(DescriptorSet* image_classes)
-      : oat_file_(NULL), image_end_(0), image_begin_(NULL), image_classes_(image_classes),
-        oat_data_begin_(NULL) {}
+  explicit ImageWriter(const CompilerDriver& compiler_driver)
+      : compiler_driver_(compiler_driver), oat_file_(NULL), image_end_(0), image_begin_(NULL),
+        oat_data_begin_(NULL), interpreter_to_interpreter_entry_offset_(0),
+        interpreter_to_quick_entry_offset_(0), portable_resolution_trampoline_offset_(0),
+        quick_resolution_trampoline_offset_(0) {}
 
   ~ImageWriter() {}
 
   bool Write(const std::string& image_filename,
              uintptr_t image_begin,
              const std::string& oat_filename,
-             const std::string& oat_location,
-             const CompilerDriver& compiler_driver)
+             const std::string& oat_location)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
   uintptr_t GetOatDataBegin() {
@@ -130,8 +130,6 @@
 
   // Remove unwanted classes from various roots.
   void PruneNonImageClasses() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static void FindClinitImageClassesCallback(mirror::Object* object, void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static bool NonImageClassesVisitor(mirror::Class* c, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -170,12 +168,14 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Patches references in OatFile to expect runtime addresses.
-  void PatchOatCodeAndMethods(const CompilerDriver& compiler)
+  void PatchOatCodeAndMethods()
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void SetPatchLocation(const CompilerDriver::PatchInformation* patch, uint32_t value)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 
+  const CompilerDriver& compiler_driver_;
+
   // Map of Object to where it will be at runtime.
   SafeMap<const mirror::Object*, size_t> offsets_;
 
@@ -191,13 +191,16 @@
   // Beginning target image address for the output image.
   byte* image_begin_;
 
-  // Set of classes to be include in the image, or NULL for all.
-  DescriptorSet* image_classes_;
-
   // Beginning target oat address for the pointers from the output image to its oat file.
   const byte* oat_data_begin_;
 
-  // DexCaches seen while scanning for fixing up CodeAndDirectMethods.
+  // Offset from oat_data_begin_ to the stubs.
+  uint32_t interpreter_to_interpreter_entry_offset_;
+  uint32_t interpreter_to_quick_entry_offset_;
+  uint32_t portable_resolution_trampoline_offset_;
+  uint32_t quick_resolution_trampoline_offset_;
+
+  // DexCaches seen while scanning for fixing up CodeAndDirectMethods
   typedef std::set<mirror::DexCache*> Set;
   Set dex_caches_;
 };
diff --git a/src/instrumentation.cc b/src/instrumentation.cc
index 39fd377..8af0885 100644
--- a/src/instrumentation.cc
+++ b/src/instrumentation.cc
@@ -62,7 +62,7 @@
         if (is_initialized || !method->IsStatic() || method->IsConstructor()) {
           new_code = class_linker->GetOatCodeFor(method);
         } else {
-          new_code = GetResolutionTrampoline();
+          new_code = GetResolutionTrampoline(class_linker);
         }
       } else {  // !uninstall
         if (!interpreter_stubs_installed_ || method->IsNative()) {
@@ -380,7 +380,7 @@
   if (LIKELY(!instrumentation_stubs_installed_)) {
     const void* code = method->GetEntryPointFromCompiledCode();
     DCHECK(code != NULL);
-    if (LIKELY(code != GetResolutionTrampoline())) {
+    if (LIKELY(code != GetResolutionTrampoline(runtime->GetClassLinker()))) {
       return code;
     }
   }
diff --git a/src/instrumentation.h b/src/instrumentation.h
index e6fa251..e79c75e 100644
--- a/src/instrumentation.h
+++ b/src/instrumentation.h
@@ -137,12 +137,24 @@
     return instrumentation_stubs_installed_;
   }
 
+  bool HasMethodEntryListeners() const {
+    return have_method_entry_listeners_;
+  }
+
+  bool HasMethodExitListeners() const {
+    return have_method_exit_listeners_;
+  }
+
+  bool HasDexPcListeners() const {
+    return have_dex_pc_listeners_;
+  }
+
   // Inform listeners that a method has been entered. A dex PC is provided as we may install
   // listeners into executing code and get method enter events for methods already on the stack.
   void MethodEnterEvent(Thread* thread, mirror::Object* this_object,
                         const mirror::AbstractMethod* method, uint32_t dex_pc) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    if (have_method_entry_listeners_) {
+    if (UNLIKELY(HasMethodEntryListeners())) {
       MethodEnterEventImpl(thread, this_object, method, dex_pc);
     }
   }
@@ -152,7 +164,7 @@
                        const mirror::AbstractMethod* method, uint32_t dex_pc,
                        const JValue& return_value) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    if (have_method_exit_listeners_) {
+    if (UNLIKELY(HasMethodExitListeners())) {
       MethodExitEventImpl(thread, this_object, method, dex_pc, return_value);
     }
   }
@@ -166,7 +178,7 @@
   void DexPcMovedEvent(Thread* thread, mirror::Object* this_object,
                        const mirror::AbstractMethod* method, uint32_t dex_pc) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    if (UNLIKELY(have_dex_pc_listeners_)) {
+    if (UNLIKELY(HasDexPcListeners())) {
       DexPcMovedEventImpl(thread, this_object, method, dex_pc);
     }
   }
diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc
index e2cc3d6..657bf43 100644
--- a/src/interpreter/interpreter.cc
+++ b/src/interpreter/interpreter.cc
@@ -50,12 +50,13 @@
 static const int64_t kMaxLong = std::numeric_limits<int64_t>::max();
 static const int64_t kMinLong = std::numeric_limits<int64_t>::min();
 
-static void UnstartedRuntimeInvoke(Thread* self, AbstractMethod* target_method,
-                                   ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
+static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh,
+                                   const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame,
+                                   JValue* result, size_t arg_offset)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // In a runtime that's not started we intercept certain methods to avoid complicated dependency
   // problems in core libraries.
-  std::string name(PrettyMethod(target_method));
+  std::string name(PrettyMethod(shadow_frame->GetMethod()));
   if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)") {
     std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset)->AsString()->ToModifiedUtf8().c_str()));
     ClassLoader* class_loader = NULL; // shadow_frame.GetMethod()->GetDeclaringClass()->GetClassLoader();
@@ -132,7 +133,7 @@
     }
   } else {
     // Not special, continue with regular interpreter execution.
-    EnterInterpreterFromInterpreter(self, shadow_frame, result);
+    artInterpreterToInterpreterEntry(self, mh, code_item, shadow_frame, result);
   }
 }
 
@@ -383,51 +384,49 @@
   ref->MonitorExit(self);
 }
 
-static void DoInvoke(Thread* self, MethodHelper& mh, ShadowFrame& shadow_frame,
-                     const Instruction* inst, InvokeType type, bool is_range,
-                     JValue* result)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
-  Object* receiver;
-  if (type == kStatic) {
-    receiver = NULL;
-  } else {
-    receiver = shadow_frame.GetVRegReference(vregC);
-  }
+// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
+// specialization.
+template<InvokeType type, bool is_range, bool do_access_check>
+static void DoInvoke(Thread* self, ShadowFrame& shadow_frame,
+                     const Instruction* inst, JValue* result) NO_THREAD_SAFETY_ANALYSIS;
+
+template<InvokeType type, bool is_range, bool do_access_check>
+static void DoInvoke(Thread* self, ShadowFrame& shadow_frame,
+                     const Instruction* inst, JValue* result) {
   uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
-  AbstractMethod* target_method = FindMethodFromCode(method_idx, receiver,
-                                                     shadow_frame.GetMethod(),
-                                                     self, true, type);
-  if (UNLIKELY(target_method == NULL)) {
+  uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
+  Object* receiver = (type == kStatic) ? NULL : shadow_frame.GetVRegReference(vregC);
+  AbstractMethod* method = FindMethodFromCode(method_idx, receiver, shadow_frame.GetMethod(), self,
+                                              do_access_check, type);
+  if (UNLIKELY(method == NULL)) {
     CHECK(self->IsExceptionPending());
     result->SetJ(0);
     return;
   }
-  MethodHelper target_mh(target_method);
 
-  const DexFile::CodeItem* code_item = target_mh.GetCodeItem();
+  MethodHelper mh(method);
+  const DexFile::CodeItem* code_item = mh.GetCodeItem();
   uint16_t num_regs;
   uint16_t num_ins;
-  if (code_item != NULL) {
+  if (LIKELY(code_item != NULL)) {
     num_regs = code_item->registers_size_;
     num_ins = code_item->ins_size_;
-  } else if (target_method->IsAbstract()) {
+  } else if (method->IsAbstract()) {
     ThrowLocation throw_location = self->GetCurrentLocationForThrow();
     self->ThrowNewExceptionF(throw_location, "Ljava/lang/AbstractMethodError;",
-                             "abstract method \"%s\"", PrettyMethod(target_method).c_str());
+                             "abstract method \"%s\"", PrettyMethod(method).c_str());
     return;
   } else {
-    DCHECK(target_method->IsNative() || target_method->IsProxyMethod());
-    num_regs = num_ins = AbstractMethod::NumArgRegisters(target_mh.GetShorty());
-    if (!target_method->IsStatic()) {
+    DCHECK(method->IsNative() || method->IsProxyMethod());
+    num_regs = num_ins = AbstractMethod::NumArgRegisters(mh.GetShorty());
+    if (!method->IsStatic()) {
       num_regs++;
       num_ins++;
     }
   }
 
   void* memory = alloca(ShadowFrame::ComputeSize(num_regs));
-  ShadowFrame* new_shadow_frame(ShadowFrame::Create(num_regs, &shadow_frame,
-                                                    target_method, 0, memory));
+  ShadowFrame* new_shadow_frame(ShadowFrame::Create(num_regs, &shadow_frame, method, 0, memory));
   size_t cur_reg = num_regs - num_ins;
   if (receiver != NULL) {
     new_shadow_frame->SetVRegReference(cur_reg, receiver);
@@ -435,13 +434,13 @@
   }
 
   size_t arg_offset = (receiver == NULL) ? 0 : 1;
-  const char* shorty = target_mh.GetShorty();
+  const char* shorty = mh.GetShorty();
   uint32_t arg[5];
   if (!is_range) {
     inst->GetArgs(arg);
   }
   for (size_t shorty_pos = 0; cur_reg < num_regs; ++shorty_pos, cur_reg++, arg_offset++) {
-    DCHECK_LT(shorty_pos + 1, target_mh.GetShortyLength());
+    DCHECK_LT(shorty_pos + 1, mh.GetShortyLength());
     size_t arg_pos = is_range ? vregC + arg_offset : arg[arg_offset];
     switch (shorty[shorty_pos + 1]) {
       case 'L': {
@@ -464,24 +463,33 @@
   }
 
   if (LIKELY(Runtime::Current()->IsStarted())) {
-    (target_method->GetEntryPointFromInterpreter())(self, new_shadow_frame, result);
+    (method->GetEntryPointFromInterpreter())(self, mh, code_item, new_shadow_frame, result);
   } else {
-    UnstartedRuntimeInvoke(self, target_method, new_shadow_frame, result, num_regs - num_ins);
+    UnstartedRuntimeInvoke(self, mh, code_item, new_shadow_frame, result, num_regs - num_ins);
   }
 }
 
+// We use template functions to optimize compiler inlining process. Otherwise,
+// some parts of the code (like a switch statement) which depend on a constant
+// parameter would not be inlined while it should be. These constant parameters
+// are now part of the template arguments.
+// Note these template functions are static and inlined so they should not be
+// part of the final object file.
+// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
+// specialization.
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
 static void DoFieldGet(Thread* self, ShadowFrame& shadow_frame,
-                       const Instruction* inst, FindFieldType find_type,
-                       Primitive::Type field_type)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE;
+                       const Instruction* inst)
+    NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
 
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
 static inline void DoFieldGet(Thread* self, ShadowFrame& shadow_frame,
-                              const Instruction* inst, FindFieldType find_type,
-                              Primitive::Type field_type) {
+                              const Instruction* inst) {
   bool is_static = (find_type == StaticObjectRead) || (find_type == StaticPrimitiveRead);
   uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
   Field* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
-                               find_type, Primitive::FieldSize(field_type));
+                               find_type, Primitive::FieldSize(field_type),
+                               do_access_check);
   if (UNLIKELY(f == NULL)) {
     CHECK(self->IsExceptionPending());
     return;
@@ -524,18 +532,21 @@
   }
 }
 
-static void DoFieldPut(Thread* self, ShadowFrame& shadow_frame,
-                       const Instruction* inst, FindFieldType find_type,
-                       Primitive::Type field_type)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE;
+// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
+// specialization.
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
+static void DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
+                       const Instruction* inst)
+    NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
 
-static inline void DoFieldPut(Thread* self, ShadowFrame& shadow_frame,
-                              const Instruction* inst, FindFieldType find_type,
-                              Primitive::Type field_type) {
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
+static inline void DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
+                              const Instruction* inst) {
   bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite);
   uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
   Field* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
-                               find_type, Primitive::FieldSize(field_type));
+                               find_type, Primitive::FieldSize(field_type),
+                               do_access_check);
   if (UNLIKELY(f == NULL)) {
     CHECK(self->IsExceptionPending());
     return;
@@ -699,11 +710,15 @@
 // Code to run before each dex instruction.
 #define PREAMBLE()
 
-static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
+// specialization.
+template<bool do_access_check>
+static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
                       ShadowFrame& shadow_frame, JValue result_register)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) __attribute__ ((hot));
+    NO_THREAD_SAFETY_ANALYSIS __attribute__ ((hot));
 
-static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+template<bool do_access_check>
+static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
                       ShadowFrame& shadow_frame, JValue result_register) {
   if (UNLIKELY(!shadow_frame.HasReferenceArray())) {
     LOG(FATAL) << "Invalid shadow frame for interpreter use";
@@ -716,12 +731,14 @@
   // As the 'this' object won't change during the execution of current code, we
   // want to cache it in local variables. Nevertheless, in order to let the
   // garbage collector access it, we store it into sirt references.
-  SirtRef<Object> this_object_ref(self, shadow_frame.GetThisObject());
+  SirtRef<Object> this_object_ref(self, shadow_frame.GetThisObject(code_item->ins_size_));
 
   const Instruction* inst = Instruction::At(insns + shadow_frame.GetDexPC());
   if (inst->GetDexPc(insns) == 0) {  // We are entering the method as opposed to deoptimizing..
-    instrumentation->MethodEnterEvent(self, this_object_ref.get(),
-                                      shadow_frame.GetMethod(), 0);
+    if (UNLIKELY(instrumentation->HasMethodEntryListeners())) {
+      instrumentation->MethodEnterEvent(self, this_object_ref.get(),
+                                        shadow_frame.GetMethod(), 0);
+    }
   }
   while (true) {
     if (UNLIKELY(self->TestAllFlags())) {
@@ -729,8 +746,10 @@
     }
     const uint32_t dex_pc = inst->GetDexPc(insns);
     shadow_frame.SetDexPC(dex_pc);
-    instrumentation->DexPcMovedEvent(self, this_object_ref.get(),
-                                     shadow_frame.GetMethod(), dex_pc);
+    if (instrumentation->HasDexPcListeners()) {
+      instrumentation->DexPcMovedEvent(self, this_object_ref.get(),
+                                       shadow_frame.GetMethod(), dex_pc);
+    }
     const bool kTracing = false;
     if (kTracing) {
 #define TRACE_LOG std::cerr
@@ -838,8 +857,11 @@
       case Instruction::RETURN_VOID: {
         PREAMBLE();
         JValue result;
-        instrumentation->MethodExitEvent(self, this_object_ref.get(),
-                                         shadow_frame.GetMethod(), inst->GetDexPc(insns), result);
+        if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
+          instrumentation->MethodExitEvent(self, this_object_ref.get(),
+                                           shadow_frame.GetMethod(), inst->GetDexPc(insns),
+                                           result);
+        }
         return result;
       }
       case Instruction::RETURN: {
@@ -847,16 +869,22 @@
         JValue result;
         result.SetJ(0);
         result.SetI(shadow_frame.GetVReg(inst->VRegA_11x()));
-        instrumentation->MethodExitEvent(self, this_object_ref.get(),
-                                         shadow_frame.GetMethod(), inst->GetDexPc(insns), result);
+        if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
+          instrumentation->MethodExitEvent(self, this_object_ref.get(),
+                                           shadow_frame.GetMethod(), inst->GetDexPc(insns),
+                                           result);
+        }
         return result;
       }
       case Instruction::RETURN_WIDE: {
         PREAMBLE();
         JValue result;
         result.SetJ(shadow_frame.GetVRegLong(inst->VRegA_11x()));
-        instrumentation->MethodExitEvent(self, this_object_ref.get(),
-                                         shadow_frame.GetMethod(), inst->GetDexPc(insns), result);
+        if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
+          instrumentation->MethodExitEvent(self, this_object_ref.get(),
+                                           shadow_frame.GetMethod(), inst->GetDexPc(insns),
+                                           result);
+        }
         return result;
       }
       case Instruction::RETURN_OBJECT: {
@@ -864,8 +892,11 @@
         JValue result;
         result.SetJ(0);
         result.SetL(shadow_frame.GetVRegReference(inst->VRegA_11x()));
-        instrumentation->MethodExitEvent(self, this_object_ref.get(),
-                                         shadow_frame.GetMethod(), inst->GetDexPc(insns), result);
+        if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
+          instrumentation->MethodExitEvent(self, this_object_ref.get(),
+                                           shadow_frame.GetMethod(), inst->GetDexPc(insns),
+                                           result);
+        }
         return result;
       }
       case Instruction::CONST_4: {
@@ -959,7 +990,7 @@
       case Instruction::CONST_CLASS: {
         PREAMBLE();
         Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(), shadow_frame.GetMethod(),
-                                          self, false, true);
+                                          self, false, do_access_check);
         if (UNLIKELY(c == NULL)) {
           HANDLE_PENDING_EXCEPTION();
         } else {
@@ -995,7 +1026,7 @@
       case Instruction::CHECK_CAST: {
         PREAMBLE();
         Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(), shadow_frame.GetMethod(),
-                                          self, false, true);
+                                          self, false, do_access_check);
         if (UNLIKELY(c == NULL)) {
           HANDLE_PENDING_EXCEPTION();
         } else {
@@ -1012,7 +1043,7 @@
       case Instruction::INSTANCE_OF: {
         PREAMBLE();
         Class* c = ResolveVerifyAndClinit(inst->VRegC_22c(), shadow_frame.GetMethod(),
-                                          self, false, true);
+                                          self, false, do_access_check);
         if (UNLIKELY(c == NULL)) {
           HANDLE_PENDING_EXCEPTION();
         } else {
@@ -1037,7 +1068,7 @@
       case Instruction::NEW_INSTANCE: {
         PREAMBLE();
         Object* obj = AllocObjectFromCode(inst->VRegB_21c(), shadow_frame.GetMethod(),
-                                          self, true);
+                                          self, do_access_check);
         if (UNLIKELY(obj == NULL)) {
           HANDLE_PENDING_EXCEPTION();
         } else {
@@ -1050,7 +1081,7 @@
         PREAMBLE();
         int32_t length = shadow_frame.GetVReg(inst->VRegB_22c());
         Object* obj = AllocArrayFromCode(inst->VRegC_22c(), shadow_frame.GetMethod(),
-                                         length, self, true);
+                                         length, self, do_access_check);
         if (UNLIKELY(obj == NULL)) {
           HANDLE_PENDING_EXCEPTION();
         } else {
@@ -1069,7 +1100,7 @@
           break;
         }
         Class* arrayClass = ResolveVerifyAndClinit(inst->VRegB_35c(), shadow_frame.GetMethod(),
-                                                   self, false, true);
+                                                   self, false, do_access_check);
         if (UNLIKELY(arrayClass == NULL)) {
           HANDLE_PENDING_EXCEPTION();
           break;
@@ -1117,7 +1148,7 @@
           break;
         }
         Class* arrayClass = ResolveVerifyAndClinit(inst->VRegB_3rc(), shadow_frame.GetMethod(),
-                                                   self, false, true);
+                                                   self, false, do_access_check);
         if (UNLIKELY(arrayClass == NULL)) {
           HANDLE_PENDING_EXCEPTION();
           break;
@@ -1193,34 +1224,34 @@
       }
       case Instruction::GOTO: {
         PREAMBLE();
-        inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegA_10t());
+        inst = inst->RelativeAt(inst->VRegA_10t());
         break;
       }
       case Instruction::GOTO_16: {
         PREAMBLE();
-        inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegA_20t());
+        inst = inst->RelativeAt(inst->VRegA_20t());
         break;
       }
       case Instruction::GOTO_32: {
         PREAMBLE();
-        inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegA_30t());
+        inst = inst->RelativeAt(inst->VRegA_30t());
         break;
       }
       case Instruction::PACKED_SWITCH: {
         PREAMBLE();
-        const uint16_t* switch_data = insns + inst->GetDexPc(insns) + inst->VRegB_31t();
+        const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
         int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t());
         DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kPackedSwitchSignature));
         uint16_t size = switch_data[1];
         DCHECK_GT(size, 0);
         const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
-        CHECK(IsAligned<4>(keys));
+        DCHECK(IsAligned<4>(keys));
         int32_t first_key = keys[0];
         const int32_t* targets = reinterpret_cast<const int32_t*>(&switch_data[4]);
         DCHECK(IsAligned<4>(targets));
         int32_t index = test_val - first_key;
         if (index >= 0 && index < size) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + targets[index]);
+          inst = inst->RelativeAt(targets[index]);
         } else {
           inst = inst->Next_3xx();
         }
@@ -1228,18 +1259,18 @@
       }
       case Instruction::SPARSE_SWITCH: {
         PREAMBLE();
-        uint32_t dex_pc = inst->GetDexPc(insns);
-        const uint16_t* switch_data = insns + dex_pc + inst->VRegB_31t();
+        const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
         int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t());
-        CHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature));
+        DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature));
         uint16_t size = switch_data[1];
-        CHECK_GT(size, 0);
+        DCHECK_GT(size, 0);
         const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
-        CHECK(IsAligned<4>(keys));
+        DCHECK(IsAligned<4>(keys));
         const int32_t* entries = keys + size;
-        CHECK(IsAligned<4>(entries));
+        DCHECK(IsAligned<4>(entries));
         int lo = 0;
         int hi = size - 1;
+        const Instruction* current_inst = inst;
         inst = inst->Next_3xx();
         while (lo <= hi) {
           int mid = (lo + hi) / 2;
@@ -1249,7 +1280,7 @@
           } else if (test_val > foundVal) {
             lo = mid + 1;
           } else {
-            inst = Instruction::At(insns + dex_pc + entries[mid]);
+            inst = current_inst->RelativeAt(entries[mid]);
             break;
           }
         }
@@ -1339,7 +1370,7 @@
       case Instruction::IF_EQ: {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_22t()) == shadow_frame.GetVReg(inst->VRegB_22t())) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegC_22t());
+          inst = inst->RelativeAt(inst->VRegC_22t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1348,7 +1379,7 @@
       case Instruction::IF_NE: {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_22t()) != shadow_frame.GetVReg(inst->VRegB_22t())) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegC_22t());
+          inst = inst->RelativeAt(inst->VRegC_22t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1357,7 +1388,7 @@
       case Instruction::IF_LT: {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_22t()) < shadow_frame.GetVReg(inst->VRegB_22t())) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegC_22t());
+          inst = inst->RelativeAt(inst->VRegC_22t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1366,7 +1397,7 @@
       case Instruction::IF_GE: {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_22t()) >= shadow_frame.GetVReg(inst->VRegB_22t())) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegC_22t());
+          inst = inst->RelativeAt(inst->VRegC_22t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1375,7 +1406,7 @@
       case Instruction::IF_GT: {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_22t()) > shadow_frame.GetVReg(inst->VRegB_22t())) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegC_22t());
+          inst = inst->RelativeAt(inst->VRegC_22t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1384,7 +1415,7 @@
       case Instruction::IF_LE: {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_22t()) <= shadow_frame.GetVReg(inst->VRegB_22t())) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegC_22t());
+          inst = inst->RelativeAt(inst->VRegC_22t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1393,7 +1424,7 @@
       case Instruction::IF_EQZ: {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_21t()) == 0) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegB_21t());
+          inst = inst->RelativeAt(inst->VRegB_21t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1402,7 +1433,7 @@
       case Instruction::IF_NEZ: {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_21t()) != 0) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegB_21t());
+          inst = inst->RelativeAt(inst->VRegB_21t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1411,7 +1442,7 @@
       case Instruction::IF_LTZ: {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_21t()) < 0) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegB_21t());
+          inst = inst->RelativeAt(inst->VRegB_21t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1420,7 +1451,7 @@
       case Instruction::IF_GEZ: {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_21t()) >= 0) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegB_21t());
+          inst = inst->RelativeAt(inst->VRegB_21t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1429,7 +1460,7 @@
       case Instruction::IF_GTZ: {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_21t()) > 0) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegB_21t());
+          inst = inst->RelativeAt(inst->VRegB_21t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1438,7 +1469,7 @@
       case Instruction::IF_LEZ:  {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_21t()) <= 0) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegB_21t());
+          inst = inst->RelativeAt(inst->VRegB_21t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1705,192 +1736,192 @@
       }
       case Instruction::IGET_BOOLEAN:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, InstancePrimitiveRead, Primitive::kPrimBoolean);
+        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IGET_BYTE:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, InstancePrimitiveRead, Primitive::kPrimByte);
+        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IGET_CHAR:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, InstancePrimitiveRead, Primitive::kPrimChar);
+        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IGET_SHORT:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, InstancePrimitiveRead, Primitive::kPrimShort);
+        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IGET:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, InstancePrimitiveRead, Primitive::kPrimInt);
+        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IGET_WIDE:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, InstancePrimitiveRead, Primitive::kPrimLong);
+        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IGET_OBJECT:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, InstanceObjectRead, Primitive::kPrimNot);
+        DoFieldGet<InstanceObjectRead, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SGET_BOOLEAN:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, StaticPrimitiveRead, Primitive::kPrimBoolean);
+        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SGET_BYTE:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, StaticPrimitiveRead, Primitive::kPrimByte);
+        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SGET_CHAR:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, StaticPrimitiveRead, Primitive::kPrimChar);
+        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SGET_SHORT:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, StaticPrimitiveRead, Primitive::kPrimShort);
+        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SGET:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, StaticPrimitiveRead, Primitive::kPrimInt);
+        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SGET_WIDE:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, StaticPrimitiveRead, Primitive::kPrimLong);
+        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SGET_OBJECT:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, StaticObjectRead, Primitive::kPrimNot);
+        DoFieldGet<StaticObjectRead, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IPUT_BOOLEAN:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, InstancePrimitiveWrite, Primitive::kPrimBoolean);
+        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IPUT_BYTE:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, InstancePrimitiveWrite, Primitive::kPrimByte);
+        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IPUT_CHAR:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, InstancePrimitiveWrite, Primitive::kPrimChar);
+        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IPUT_SHORT:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, InstancePrimitiveWrite, Primitive::kPrimShort);
+        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IPUT:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, InstancePrimitiveWrite, Primitive::kPrimInt);
+        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IPUT_WIDE:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, InstancePrimitiveWrite, Primitive::kPrimLong);
+        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IPUT_OBJECT:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, InstanceObjectWrite, Primitive::kPrimNot);
+        DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SPUT_BOOLEAN:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, StaticPrimitiveWrite, Primitive::kPrimBoolean);
+        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SPUT_BYTE:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, StaticPrimitiveWrite, Primitive::kPrimByte);
+        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SPUT_CHAR:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, StaticPrimitiveWrite, Primitive::kPrimChar);
+        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SPUT_SHORT:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, StaticPrimitiveWrite, Primitive::kPrimShort);
+        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SPUT:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, StaticPrimitiveWrite, Primitive::kPrimInt);
+        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SPUT_WIDE:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, StaticPrimitiveWrite, Primitive::kPrimLong);
+        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SPUT_OBJECT:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, StaticObjectWrite, Primitive::kPrimNot);
+        DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::INVOKE_VIRTUAL:
         PREAMBLE();
-        DoInvoke(self, mh, shadow_frame, inst, kVirtual, false, &result_register);
+        DoInvoke<kVirtual, false, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_VIRTUAL_RANGE:
         PREAMBLE();
-        DoInvoke(self, mh, shadow_frame, inst, kVirtual, true, &result_register);
+        DoInvoke<kVirtual, true, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_SUPER:
         PREAMBLE();
-        DoInvoke(self, mh, shadow_frame, inst, kSuper, false, &result_register);
+        DoInvoke<kSuper, false, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_SUPER_RANGE:
         PREAMBLE();
-        DoInvoke(self, mh, shadow_frame, inst, kSuper, true, &result_register);
+        DoInvoke<kSuper, true, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_DIRECT:
         PREAMBLE();
-        DoInvoke(self, mh, shadow_frame, inst, kDirect, false, &result_register);
+        DoInvoke<kDirect, false, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_DIRECT_RANGE:
         PREAMBLE();
-        DoInvoke(self, mh, shadow_frame, inst, kDirect, true, &result_register);
+        DoInvoke<kDirect, true, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_INTERFACE:
         PREAMBLE();
-        DoInvoke(self, mh, shadow_frame, inst, kInterface, false, &result_register);
+        DoInvoke<kInterface, false, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_INTERFACE_RANGE:
         PREAMBLE();
-        DoInvoke(self, mh, shadow_frame, inst, kInterface, true, &result_register);
+        DoInvoke<kInterface, true, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_STATIC:
         PREAMBLE();
-        DoInvoke(self, mh, shadow_frame, inst, kStatic, false, &result_register);
+        DoInvoke<kStatic, false, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_STATIC_RANGE:
         PREAMBLE();
-        DoInvoke(self, mh, shadow_frame, inst, kStatic, true, &result_register);
+        DoInvoke<kStatic, true, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::NEG_INT:
@@ -2296,6 +2327,14 @@
         inst = inst->Next_1xx();
         break;
       }
+      case Instruction::DIV_INT_2ADDR: {
+        PREAMBLE();
+        uint32_t vregA = inst->VRegA_12x();
+        DoIntDivide(self, shadow_frame, vregA, shadow_frame.GetVReg(vregA),
+                    shadow_frame.GetVReg(inst->VRegB_12x()));
+        inst = inst->Next_1xx();
+        break;
+      }
       case Instruction::REM_INT_2ADDR: {
         PREAMBLE();
         uint32_t vregA = inst->VRegA_12x();
@@ -2358,14 +2397,6 @@
         inst = inst->Next_1xx();
         break;
       }
-      case Instruction::DIV_INT_2ADDR: {
-        PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
-        DoIntDivide(self, shadow_frame, vregA, shadow_frame.GetVReg(vregA),
-                    shadow_frame.GetVReg(inst->VRegB_12x()));
-        inst = inst->Next_1xx();
-        break;
-      }
       case Instruction::ADD_LONG_2ADDR: {
         PREAMBLE();
         uint32_t vregA = inst->VRegA_12x();
@@ -2692,10 +2723,25 @@
   }
 }
 
+static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+                      ShadowFrame& shadow_frame, JValue result_register)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+static inline JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+                             ShadowFrame& shadow_frame, JValue result_register) {
+  if (shadow_frame.GetMethod()->IsPreverified()) {
+    // Enter the "without access check" interpreter.
+    return ExecuteImpl<false>(self, mh, code_item, shadow_frame, result_register);
+  } else {
+    // Enter the "with access check" interpreter.
+    return ExecuteImpl<true>(self, mh, code_item, shadow_frame, result_register);
+  }
+}
+
 void EnterInterpreterFromInvoke(Thread* self, AbstractMethod* method, Object* receiver,
                                 uint32_t* args, JValue* result) {
   DCHECK_EQ(self, Thread::Current());
-  if (__builtin_frame_address(0) < self->GetStackEnd()) {
+  if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEnd())) {
     ThrowStackOverflowError(self);
     return;
   }
@@ -2799,7 +2845,7 @@
                                 ShadowFrame& shadow_frame)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   DCHECK_EQ(self, Thread::Current());
-  if (__builtin_frame_address(0) < self->GetStackEnd()) {
+  if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEnd())) {
     ThrowStackOverflowError(self);
     return JValue();
   }
@@ -2807,9 +2853,11 @@
   return Execute(self, mh, code_item, shadow_frame, JValue());
 }
 
-void EnterInterpreterFromInterpreter(Thread* self, ShadowFrame* shadow_frame, JValue* result)
+void artInterpreterToInterpreterEntry(Thread* self, MethodHelper& mh,
+                                      const DexFile::CodeItem* code_item,
+                                      ShadowFrame* shadow_frame, JValue* result)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  if (__builtin_frame_address(0) < self->GetStackEnd()) {
+  if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEnd())) {
     ThrowStackOverflowError(self);
     return;
   }
@@ -2826,8 +2874,6 @@
 
   self->PushShadowFrame(shadow_frame);
 
-  MethodHelper mh(method);
-  const DexFile::CodeItem* code_item = mh.GetCodeItem();
   if (LIKELY(!method->IsNative())) {
     result->SetJ(Execute(self, mh, code_item, *shadow_frame, JValue()).GetJ());
   } else {
diff --git a/src/interpreter/interpreter.h b/src/interpreter/interpreter.h
index 96fa050..20166ac 100644
--- a/src/interpreter/interpreter.h
+++ b/src/interpreter/interpreter.h
@@ -47,7 +47,9 @@
                                        ShadowFrame& shadow_frame)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-extern void EnterInterpreterFromInterpreter(Thread* self, ShadowFrame* shadow_frame, JValue* result)
+extern "C" void artInterpreterToInterpreterEntry(Thread* self, MethodHelper& mh,
+                                                const DexFile::CodeItem* code_item,
+                                                ShadowFrame* shadow_frame, JValue* result)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 }  // namespace interpreter
diff --git a/src/locks.cc b/src/locks.cc
index eb0620c..51a40c3 100644
--- a/src/locks.cc
+++ b/src/locks.cc
@@ -22,7 +22,7 @@
 
 Mutex* Locks::abort_lock_ = NULL;
 Mutex* Locks::breakpoint_lock_ = NULL;
-Mutex* Locks::classlinker_classes_lock_ = NULL;
+ReaderWriterMutex* Locks::classlinker_classes_lock_ = NULL;
 ReaderWriterMutex* Locks::heap_bitmap_lock_ = NULL;
 Mutex* Locks::logging_lock_ = NULL;
 ReaderWriterMutex* Locks::mutator_lock_ = NULL;
@@ -52,7 +52,8 @@
     DCHECK(breakpoint_lock_ == NULL);
     breakpoint_lock_ = new Mutex("breakpoint lock", kBreakpointLock);
     DCHECK(classlinker_classes_lock_ == NULL);
-    classlinker_classes_lock_ = new Mutex("ClassLinker classes lock", kClassLinkerClassesLock);
+    classlinker_classes_lock_ = new ReaderWriterMutex("ClassLinker classes lock",
+                                                      kClassLinkerClassesLock);
     DCHECK(heap_bitmap_lock_ == NULL);
     heap_bitmap_lock_ = new ReaderWriterMutex("heap bitmap lock", kHeapBitmapLock);
     DCHECK(mutator_lock_ == NULL);
diff --git a/src/locks.h b/src/locks.h
index 431a148..ceb04b9 100644
--- a/src/locks.h
+++ b/src/locks.h
@@ -143,7 +143,7 @@
   static Mutex* trace_lock_ ACQUIRED_AFTER(breakpoint_lock_);
 
   // Guards lists of classes within the class linker.
-  static Mutex* classlinker_classes_lock_ ACQUIRED_AFTER(trace_lock_);
+  static ReaderWriterMutex* classlinker_classes_lock_ ACQUIRED_AFTER(trace_lock_);
 
   // When declaring any Mutex add DEFAULT_MUTEX_ACQUIRED_AFTER to use annotalysis to check the code
   // doesn't try to hold a higher level Mutex.
diff --git a/src/mirror/abstract_method-inl.h b/src/mirror/abstract_method-inl.h
index d4f0f2c..a823886 100644
--- a/src/mirror/abstract_method-inl.h
+++ b/src/mirror/abstract_method-inl.h
@@ -117,7 +117,8 @@
   if (GetEntryPointFromCompiledCode() == GetInterpreterEntryPoint()) {
     return;
   }
-  if (GetEntryPointFromCompiledCode() == GetResolutionTrampoline()) {
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  if (GetEntryPointFromCompiledCode() == GetResolutionTrampoline(class_linker)) {
       return;
   }
   DCHECK(IsWithinCode(pc))
diff --git a/src/mirror/abstract_method.cc b/src/mirror/abstract_method.cc
index 5258795..c2ab29e 100644
--- a/src/mirror/abstract_method.cc
+++ b/src/mirror/abstract_method.cc
@@ -268,45 +268,28 @@
       result->SetJ(0);
     }
   } else {
-    bool interpret = runtime->GetInstrumentation()->InterpretOnly() && !IsNative() &&
-        !IsProxyMethod();
     const bool kLogInvocationStartAndReturn = false;
     if (GetEntryPointFromCompiledCode() != NULL) {
-      if (!interpret) {
-        if (kLogInvocationStartAndReturn) {
-          LOG(INFO) << StringPrintf("Invoking '%s' code=%p", PrettyMethod(this).c_str(), GetEntryPointFromCompiledCode());
-        }
+      if (kLogInvocationStartAndReturn) {
+        LOG(INFO) << StringPrintf("Invoking '%s' code=%p", PrettyMethod(this).c_str(), GetEntryPointFromCompiledCode());
+      }
 #ifdef ART_USE_PORTABLE_COMPILER
-        (*art_portable_invoke_stub)(this, args, args_size, self, result, result_type);
+      (*art_portable_invoke_stub)(this, args, args_size, self, result, result_type);
 #else
-        (*art_quick_invoke_stub)(this, args, args_size, self, result, result_type);
+      (*art_quick_invoke_stub)(this, args, args_size, self, result, result_type);
 #endif
-        if (UNLIKELY(reinterpret_cast<int32_t>(self->GetException(NULL)) == -1)) {
-          // Unusual case where we were running LLVM generated code and an
-          // exception was thrown to force the activations to be removed from the
-          // stack. Continue execution in the interpreter.
-          self->ClearException();
-          ShadowFrame* shadow_frame = self->GetAndClearDeoptimizationShadowFrame(result);
-          self->SetTopOfStack(NULL, 0);
-          self->SetTopOfShadowStack(shadow_frame);
-          interpreter::EnterInterpreterFromDeoptimize(self, shadow_frame, result);
-        }
-        if (kLogInvocationStartAndReturn) {
-          LOG(INFO) << StringPrintf("Returned '%s' code=%p", PrettyMethod(this).c_str(), GetEntryPointFromCompiledCode());
-        }
-      } else {
-        if (kLogInvocationStartAndReturn) {
-          LOG(INFO) << "Interpreting " << PrettyMethod(this) << "'";
-        }
-        if (this->IsStatic()) {
-          art::interpreter::EnterInterpreterFromInvoke(self, this, NULL, args, result);
-        } else {
-          Object* receiver = reinterpret_cast<Object*>(args[0]);
-          art::interpreter::EnterInterpreterFromInvoke(self, this, receiver, args + 1, result);
-        }
-        if (kLogInvocationStartAndReturn) {
-          LOG(INFO) << "Returned '" << PrettyMethod(this) << "'";
-        }
+      if (UNLIKELY(reinterpret_cast<int32_t>(self->GetException(NULL)) == -1)) {
+        // Unusual case where we were running LLVM generated code and an
+        // exception was thrown to force the activations to be removed from the
+        // stack. Continue execution in the interpreter.
+        self->ClearException();
+        ShadowFrame* shadow_frame = self->GetAndClearDeoptimizationShadowFrame(result);
+        self->SetTopOfStack(NULL, 0);
+        self->SetTopOfShadowStack(shadow_frame);
+        interpreter::EnterInterpreterFromDeoptimize(self, shadow_frame, result);
+      }
+      if (kLogInvocationStartAndReturn) {
+        LOG(INFO) << StringPrintf("Returned '%s' code=%p", PrettyMethod(this).c_str(), GetEntryPointFromCompiledCode());
       }
     } else {
       LOG(INFO) << "Not invoking '" << PrettyMethod(this)
diff --git a/src/mirror/abstract_method.h b/src/mirror/abstract_method.h
index c8aa11e..339471d 100644
--- a/src/mirror/abstract_method.h
+++ b/src/mirror/abstract_method.h
@@ -18,6 +18,7 @@
 #define ART_SRC_MIRROR_METHOD_H_
 
 #include "class.h"
+#include "dex_file.h"
 #include "invoke_type.h"
 #include "locks.h"
 #include "modifiers.h"
@@ -29,6 +30,7 @@
 struct ConstructorMethodOffsets;
 union JValue;
 struct MethodClassOffsets;
+class MethodHelper;
 struct MethodOffsets;
 class StringPiece;
 class ShadowFrame;
@@ -37,7 +39,8 @@
 
 class StaticStorageBase;
 
-typedef void (EntryPointFromInterpreter)(Thread* self, ShadowFrame* shadow_frame, JValue* result);
+typedef void (EntryPointFromInterpreter)(Thread* self, MethodHelper& mh,
+    const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, JValue* result);
 
 // C++ mirror of java.lang.reflect.Method and java.lang.reflect.Constructor
 class MANAGED AbstractMethod : public Object {
@@ -120,6 +123,14 @@
 
   bool IsProxyMethod() const;
 
+  bool IsPreverified() const {
+    return (GetAccessFlags() & kAccPreverified) != 0;
+  }
+
+  void SetPreverified() {
+    SetAccessFlags(GetAccessFlags() | kAccPreverified);
+  }
+
   bool CheckIncompatibleClassChange(InvokeType type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   uint16_t GetMethodIndex() const;
diff --git a/src/mirror/class.cc b/src/mirror/class.cc
index 15129ab..2dae90c 100644
--- a/src/mirror/class.cc
+++ b/src/mirror/class.cc
@@ -604,5 +604,22 @@
   return NULL;
 }
 
+static void SetPreverifiedFlagOnMethods(mirror::ObjectArray<mirror::AbstractMethod>* methods)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (methods != NULL) {
+    for (int32_t index = 0, end = methods->GetLength(); index < end; ++index) {
+      mirror::AbstractMethod* method = methods->GetWithoutChecks(index);
+      DCHECK(method != NULL);
+      method->SetPreverified();
+    }
+  }
+}
+
+void Class::SetPreverifiedFlagOnAllMethods() {
+  DCHECK(IsVerified());
+  SetPreverifiedFlagOnMethods(GetDirectMethods());
+  SetPreverifiedFlagOnMethods(GetVirtualMethods());
+}
+
 }  // namespace mirror
 }  // namespace art
diff --git a/src/mirror/class.h b/src/mirror/class.h
index 0661b42..084aa24 100644
--- a/src/mirror/class.h
+++ b/src/mirror/class.h
@@ -235,6 +235,23 @@
     return (GetAccessFlags() & kAccClassIsPhantomReference) != 0;
   }
 
+  // Can references of this type be assigned to by things of another type? For non-array types
+  // this is a matter of whether sub-classes may exist - which they can't if the type is final.
+  // For array classes, where all the classes are final due to there being no sub-classes, an
+  // Object[] may be assigned to by a String[] but a String[] may not be assigned to by other
+  // types as the component is final.
+  bool CannotBeAssignedFromOtherTypes() const {
+    if (!IsArrayClass()) {
+      return IsFinal();
+    } else {
+      Class* component = GetComponentType();
+      if (component->IsPrimitive()) {
+        return false;
+      } else {
+        return component->CannotBeAssignedFromOtherTypes();
+      }
+    }
+  }
 
   String* GetName() const;  // Returns the cached name.
   void SetName(String* name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);  // Sets the cached name.
@@ -726,6 +743,9 @@
   static void SetClassClass(Class* java_lang_Class);
   static void ResetClass();
 
+  // When class is verified, set the kAccPreverified flag on each method.
+  void SetPreverifiedFlagOnAllMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
  private:
   void SetVerifyErrorClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
diff --git a/src/mirror/dex_cache-inl.h b/src/mirror/dex_cache-inl.h
new file mode 100644
index 0000000..3b17c42
--- /dev/null
+++ b/src/mirror/dex_cache-inl.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2013 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_MIRROR_DEX_CACHE_INL_H_
+#define ART_SRC_MIRROR_DEX_CACHE_INL_H_
+
+#include "dex_cache.h"
+
+namespace art {
+namespace mirror {
+
+inline AbstractMethod* DexCache::GetResolvedMethod(uint32_t method_idx) const
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  AbstractMethod* method = GetResolvedMethods()->Get(method_idx);
+  // Hide resolution trampoline methods from the caller
+  if (method != NULL && method->IsRuntimeMethod()) {
+    DCHECK(method == Runtime::Current()->GetResolutionMethod());
+    return NULL;
+  } else {
+    return method;
+  }
+}
+
+}  // namespace mirror
+}  // namespace art
+
+#endif  // ART_SRC_MIRROR_DEX_CACHE_INL_H_
diff --git a/src/mirror/dex_cache.cc b/src/mirror/dex_cache.cc
index 3009786..d9c05fb 100644
--- a/src/mirror/dex_cache.cc
+++ b/src/mirror/dex_cache.cc
@@ -78,17 +78,5 @@
   }
 }
 
-AbstractMethod* DexCache::GetResolvedMethod(uint32_t method_idx) const
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  AbstractMethod* method = GetResolvedMethods()->Get(method_idx);
-  // Hide resolution trampoline methods from the caller
-  if (method != NULL && method->IsRuntimeMethod()) {
-    DCHECK(method == Runtime::Current()->GetResolutionMethod());
-    return NULL;
-  } else {
-    return method;
-  }
-}
-
 }  // namespace mirror
 }  // namespace art
diff --git a/src/mirror/object_test.cc b/src/mirror/object_test.cc
index abf6c29..52df544 100644
--- a/src/mirror/object_test.cc
+++ b/src/mirror/object_test.cc
@@ -283,7 +283,7 @@
   uint32_t field_idx = dex_file->GetIndexForFieldId(*field_id);
 
   Field* field = FindFieldFromCode(field_idx, clinit, Thread::Current(), StaticObjectRead,
-                                   sizeof(Object*));
+                                   sizeof(Object*), true);
   Object* s0 = field->GetObj(klass);
   EXPECT_TRUE(s0 != NULL);
 
diff --git a/src/modifiers.h b/src/modifiers.h
index a15b096..85bc06d 100644
--- a/src/modifiers.h
+++ b/src/modifiers.h
@@ -46,7 +46,9 @@
 static const uint32_t kAccDeclaredSynchronized = 0x00020000;  // method (dex only)
 static const uint32_t kAccClassIsProxy = 0x00040000;  // class (dex only)
 // TODO: JACK CLASS ACCESS (HACK TO BE REMOVED)
-static const uint32_t kAccClassJack = 0x000080000;  // class (dex only)
+static const uint32_t kAccClassJack = 0x00080000;  // class (dex only)
+
+static const uint32_t kAccPreverified = 0x00100000;  // method (dex only)
 
 // Special runtime-only flags.
 // Note: if only kAccClassIsReference is set, we have a soft reference.
diff --git a/src/oat.cc b/src/oat.cc
index 4eb97f5..e606953 100644
--- a/src/oat.cc
+++ b/src/oat.cc
@@ -22,7 +22,7 @@
 namespace art {
 
 const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
-const uint8_t OatHeader::kOatVersion[] = { '0', '0', '5', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '0', '6', '\0' };
 
 OatHeader::OatHeader() {
   memset(this, 0, sizeof(*this));
@@ -57,6 +57,10 @@
   UpdateChecksum(image_file_location.data(), image_file_location_size_);
 
   executable_offset_ = 0;
+  interpreter_to_interpreter_entry_offset_ = 0;
+  interpreter_to_quick_entry_offset_ = 0;
+  portable_resolution_trampoline_offset_ = 0;
+  quick_resolution_trampoline_offset_ = 0;
 }
 
 bool OatHeader::IsValid() const {
@@ -97,6 +101,92 @@
   return executable_offset_;
 }
 
+void OatHeader::SetExecutableOffset(uint32_t executable_offset) {
+  DCHECK_ALIGNED(executable_offset, kPageSize);
+  CHECK_GT(executable_offset, sizeof(OatHeader));
+  DCHECK(IsValid());
+  DCHECK_EQ(executable_offset_, 0U);
+
+  executable_offset_ = executable_offset;
+  UpdateChecksum(&executable_offset_, sizeof(executable_offset));
+}
+
+const void* OatHeader::GetInterpreterToInterpreterEntry() const {
+  return reinterpret_cast<const uint8_t*>(this) + GetInterpreterToInterpreterEntryOffset();
+}
+
+uint32_t OatHeader::GetInterpreterToInterpreterEntryOffset() const {
+  DCHECK(IsValid());
+  CHECK_GE(interpreter_to_interpreter_entry_offset_, executable_offset_);
+  return interpreter_to_interpreter_entry_offset_;
+}
+
+void OatHeader::SetInterpreterToInterpreterEntryOffset(uint32_t offset) {
+  CHECK(offset == 0 || offset >= executable_offset_);
+  DCHECK(IsValid());
+  DCHECK_EQ(interpreter_to_interpreter_entry_offset_, 0U) << offset;
+
+  interpreter_to_interpreter_entry_offset_ = offset;
+  UpdateChecksum(&interpreter_to_interpreter_entry_offset_, sizeof(offset));
+}
+
+const void* OatHeader::GetInterpreterToQuickEntry() const {
+  return reinterpret_cast<const uint8_t*>(this) + GetInterpreterToQuickEntryOffset();
+}
+
+uint32_t OatHeader::GetInterpreterToQuickEntryOffset() const {
+  DCHECK(IsValid());
+  CHECK_GE(interpreter_to_quick_entry_offset_, interpreter_to_interpreter_entry_offset_);
+  return interpreter_to_quick_entry_offset_;
+}
+
+void OatHeader::SetInterpreterToQuickEntryOffset(uint32_t offset) {
+  CHECK(offset == 0 || offset >= interpreter_to_interpreter_entry_offset_);
+  DCHECK(IsValid());
+  DCHECK_EQ(interpreter_to_quick_entry_offset_, 0U) << offset;
+
+  interpreter_to_quick_entry_offset_ = offset;
+  UpdateChecksum(&interpreter_to_quick_entry_offset_, sizeof(offset));
+}
+
+const void* OatHeader::GetPortableResolutionTrampoline() const {
+  return reinterpret_cast<const uint8_t*>(this) + GetPortableResolutionTrampolineOffset();
+}
+
+uint32_t OatHeader::GetPortableResolutionTrampolineOffset() const {
+  DCHECK(IsValid());
+  CHECK_GE(portable_resolution_trampoline_offset_, interpreter_to_quick_entry_offset_);
+  return portable_resolution_trampoline_offset_;
+}
+
+void OatHeader::SetPortableResolutionTrampolineOffset(uint32_t offset) {
+  CHECK(offset == 0 || offset >= interpreter_to_quick_entry_offset_);
+  DCHECK(IsValid());
+  DCHECK_EQ(portable_resolution_trampoline_offset_, 0U) << offset;
+
+  portable_resolution_trampoline_offset_ = offset;
+  UpdateChecksum(&portable_resolution_trampoline_offset_, sizeof(offset));
+}
+
+const void* OatHeader::GetQuickResolutionTrampoline() const {
+  return reinterpret_cast<const uint8_t*>(this) + GetQuickResolutionTrampolineOffset();
+}
+
+uint32_t OatHeader::GetQuickResolutionTrampolineOffset() const {
+  DCHECK(IsValid());
+  CHECK_GE(quick_resolution_trampoline_offset_, portable_resolution_trampoline_offset_);
+  return quick_resolution_trampoline_offset_;
+}
+
+void OatHeader::SetQuickResolutionTrampolineOffset(uint32_t offset) {
+  CHECK(offset == 0 || offset >= portable_resolution_trampoline_offset_);
+  DCHECK(IsValid());
+  DCHECK_EQ(quick_resolution_trampoline_offset_, 0U) << offset;
+
+  quick_resolution_trampoline_offset_ = offset;
+  UpdateChecksum(&quick_resolution_trampoline_offset_, sizeof(offset));
+}
+
 uint32_t OatHeader::GetImageFileLocationOatChecksum() const {
   CHECK(IsValid());
   return image_file_location_oat_checksum_;
@@ -123,16 +213,6 @@
                      GetImageFileLocationSize());
 }
 
-void OatHeader::SetExecutableOffset(uint32_t executable_offset) {
-  DCHECK_ALIGNED(executable_offset, kPageSize);
-  CHECK_GT(executable_offset, sizeof(OatHeader));
-  DCHECK(IsValid());
-  DCHECK_EQ(executable_offset_, 0U);
-
-  executable_offset_ = executable_offset;
-  UpdateChecksum(&executable_offset_, sizeof(executable_offset));
-}
-
 OatMethodOffsets::OatMethodOffsets()
   : code_offset_(0),
     frame_size_in_bytes_(0),
diff --git a/src/oat.h b/src/oat.h
index cf98891..c67a1a6 100644
--- a/src/oat.h
+++ b/src/oat.h
@@ -43,8 +43,20 @@
     return dex_file_count_;
   }
   uint32_t GetExecutableOffset() const;
-  InstructionSet GetInstructionSet() const;
   void SetExecutableOffset(uint32_t executable_offset);
+  const void* GetInterpreterToInterpreterEntry() const;
+  uint32_t GetInterpreterToInterpreterEntryOffset() const;
+  void SetInterpreterToInterpreterEntryOffset(uint32_t offset);
+  const void* GetInterpreterToQuickEntry() const;
+  uint32_t GetInterpreterToQuickEntryOffset() const;
+  void SetInterpreterToQuickEntryOffset(uint32_t offset);
+  const void* GetPortableResolutionTrampoline() const;
+  uint32_t GetPortableResolutionTrampolineOffset() const;
+  void SetPortableResolutionTrampolineOffset(uint32_t offset);
+  const void* GetQuickResolutionTrampoline() const;
+  uint32_t GetQuickResolutionTrampolineOffset() const;
+  void SetQuickResolutionTrampolineOffset(uint32_t offset);
+  InstructionSet GetInstructionSet() const;
   uint32_t GetImageFileLocationOatChecksum() const;
   uint32_t GetImageFileLocationOatDataBegin() const;
   uint32_t GetImageFileLocationSize() const;
@@ -62,6 +74,10 @@
   InstructionSet instruction_set_;
   uint32_t dex_file_count_;
   uint32_t executable_offset_;
+  uint32_t interpreter_to_interpreter_entry_offset_;
+  uint32_t interpreter_to_quick_entry_offset_;
+  uint32_t portable_resolution_trampoline_offset_;
+  uint32_t quick_resolution_trampoline_offset_;
 
   uint32_t image_file_location_oat_checksum_;
   uint32_t image_file_location_oat_data_begin_;
diff --git a/src/oat/runtime/arm/oat_support_entrypoints_arm.cc b/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
index 1a5fe47..2e9453c 100644
--- a/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
+++ b/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
@@ -91,12 +91,26 @@
 extern "C" uint64_t art_quick_shr_long(uint64_t, uint32_t);
 extern "C" uint64_t art_quick_ushr_long(uint64_t, uint32_t);
 
+// Interpreter entrypoints.
+extern "C" void artInterpreterToInterpreterEntry(Thread* self, MethodHelper& mh,
+                                                 const DexFile::CodeItem* code_item,
+                                                 ShadowFrame* shadow_frame, JValue* result);
+extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh,
+                                           const DexFile::CodeItem* code_item,
+                                           ShadowFrame* shadow_frame, JValue* result);
+
 // Intrinsic entrypoints.
 extern "C" int32_t __memcmp16(void*, void*, int32_t);
 extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t);
 extern "C" int32_t art_quick_string_compareto(void*, void*);
 
 // Invoke entrypoints.
+extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called,
+                                                       mirror::Object* receiver,
+                                                       mirror::AbstractMethod** sp, Thread* thread);
+extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* called,
+                                                    mirror::Object* receiver,
+                                                    mirror::AbstractMethod** sp, Thread* thread);
 extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*);
 extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*);
 extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*);
@@ -187,6 +201,10 @@
   points->pShrLong = art_quick_shr_long;
   points->pUshrLong = art_quick_ushr_long;
 
+  // Interpreter
+  points->pInterpreterToInterpreterEntry = artInterpreterToInterpreterEntry;
+  points->pInterpreterToQuickEntry = artInterpreterToQuickEntry;
+
   // Intrinsics
   points->pIndexOf = art_quick_indexof;
   points->pMemcmp16 = __memcmp16;
@@ -194,6 +212,8 @@
   points->pMemcpy = memcpy;
 
   // Invocation
+  points->pPortableResolutionTrampolineFromCode = artPortableResolutionTrampoline;
+  points->pQuickResolutionTrampolineFromCode = artQuickResolutionTrampoline;
   points->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check;
   points->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline;
   points->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check;
diff --git a/src/oat/runtime/arm/runtime_support_arm.S b/src/oat/runtime/arm/runtime_support_arm.S
index 3578ba0..f19e8ba 100644
--- a/src/oat/runtime/arm/runtime_support_arm.S
+++ b/src/oat/runtime/arm/runtime_support_arm.S
@@ -246,48 +246,6 @@
 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
-ENTRY art_portable_resolution_trampoline
-    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    r2, r9                         @ pass Thread::Current
-    mov    r1, sp                         @ pass stack pointer
-    blx    artPortableResolutionTrampoline   @ (method_idx, sp, Thread*)
-    mov    r12, r0                        @ save method code pointer result
-    add    sp, #12                        @ remove padding from 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_portable_resolution_trampoline
-
-    /*
-     * Quick resolution trampoline.
-     */
-     .extern artQuickResolutionTrampoline
-ENTRY art_quick_resolution_trampoline
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME  @ save callee saves in case allocation triggers GC
-    mov    r2, r9                         @ pass Thread::Current
-    mov    r1, sp                         @ pass stack pointer
-    blx    artQuickResolutionTrampoline   @ (method_idx, sp, Thread*)
-    mov    r12, r0                        @ save method code pointer result
-    add    sp, #4                         @ set up stack pointer
-    .cfi_adjust_cfa_offset -4
-    pop    {r0-r3, r5-r8, r10-r11, lr}    @ 11 words, r0 will hold method*
-    .cfi_adjust_cfa_offset -44
-    bx     r12                            @ leaf call to method code
-END art_quick_resolution_trampoline
-
     /*
      * Portable invocation stub.
      * On entry:
diff --git a/src/oat/runtime/mips/oat_support_entrypoints_mips.cc b/src/oat/runtime/mips/oat_support_entrypoints_mips.cc
index eb82c42..8e06611 100644
--- a/src/oat/runtime/mips/oat_support_entrypoints_mips.cc
+++ b/src/oat/runtime/mips/oat_support_entrypoints_mips.cc
@@ -93,12 +93,26 @@
 extern "C" uint64_t art_quick_shr_long(uint64_t, uint32_t);
 extern "C" uint64_t art_quick_ushr_long(uint64_t, uint32_t);
 
+// Interpreter entrypoints.
+extern "C" void artInterpreterToInterpreterEntry(Thread* self, MethodHelper& mh,
+                                                 const DexFile::CodeItem* code_item,
+                                                 ShadowFrame* shadow_frame, JValue* result);
+extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh,
+                                           const DexFile::CodeItem* code_item,
+                                           ShadowFrame* shadow_frame, JValue* result);
+
 // Intrinsic entrypoints.
 extern "C" int32_t __memcmp16(void*, void*, int32_t);
 extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t);
 extern "C" int32_t art_quick_string_compareto(void*, void*);
 
 // Invoke entrypoints.
+extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called,
+                                                       mirror::Object* receiver,
+                                                       mirror::AbstractMethod** sp, Thread* thread);
+extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* called,
+                                                    mirror::Object* receiver,
+                                                    mirror::AbstractMethod** sp, Thread* thread);
 extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*);
 extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*);
 extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*);
@@ -188,6 +202,10 @@
   points->pShrLong = art_quick_shr_long;
   points->pUshrLong = art_quick_ushr_long;
 
+  // Interpreter
+  points->pInterpreterToInterpreterEntry = artInterpreterToInterpreterEntry;
+  points->pInterpreterToQuickEntry = artInterpreterToQuickEntry;
+
   // Intrinsics
   points->pIndexOf = art_quick_indexof;
   points->pMemcmp16 = __memcmp16;
@@ -195,6 +213,8 @@
   points->pMemcpy = memcpy;
 
   // Invocation
+  points->pPortableResolutionTrampolineFromCode = artPortableResolutionTrampoline;
+  points->pQuickResolutionTrampolineFromCode = artQuickResolutionTrampoline;
   points->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check;
   points->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline;
   points->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check;
diff --git a/src/oat/runtime/mips/runtime_support_mips.S b/src/oat/runtime/mips/runtime_support_mips.S
index 2144e34..45d583e 100644
--- a/src/oat/runtime/mips/runtime_support_mips.S
+++ b/src/oat/runtime/mips/runtime_support_mips.S
@@ -413,71 +413,6 @@
 INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
 
     /*
-     * Portable resolution trampoline.
-     */
-    .extern artPortableResolutionTrampoline
-ENTRY art_portable_resolution_trampoline
-    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
-    move  $a2, $s1              # pass Thread::Current()
-    jal   artPortableResolutionTrampoline  # (method_idx, sp, Thread*)
-    move  $a1, $sp              # pass stack pointer
-    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, resolve_fail
-    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
-resolve_fail:
-    jr    $ra
-    nop
-END art_portable_resolution_trampoline
-
-    /*
-     * Quick resolution trampoline.
-     */
-    .extern artQuickResolutionTrampoline
-ENTRY art_quick_resolution_trampoline
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    move  $a2, $s1              # pass Thread::Current()
-    jal   artQuickResolutionTrampoline  # (method_idx, sp, Thread*)
-    move  $a1, $sp              # pass stack pointer
-    move  $t9, $v0              # put method code result in $t9
-    lw    $a0, 0($sp)           # restore registers from stack
-    lw    $a1, 4($sp)
-    lw    $a2, 8($sp)
-    lw    $a3, 12($sp)
-    lw    $s2, 28($sp)
-    lw    $s3, 32($sp)
-    lw    $s4, 36($sp)
-    lw    $s5, 40($sp)
-    lw    $s6, 44($sp)
-    lw    $s7, 48($sp)
-    lw    $gp, 52($sp)
-    lw    $fp, 56($sp)
-    lw    $ra, 60($sp)
-    jr    $t9                   # leaf call to method's code
-    addiu $sp, $sp, 64          # restore the stack
-    .cfi_adjust_cfa_offset -64
-END art_quick_resolution_trampoline
-
-    /*
      * Common invocation stub for portable and quick.
      * On entry:
      *   a0 = method pointer
diff --git a/src/oat/runtime/oat_support_entrypoints.h b/src/oat/runtime/oat_support_entrypoints.h
index 72d5348..c1a2587 100644
--- a/src/oat/runtime/oat_support_entrypoints.h
+++ b/src/oat/runtime/oat_support_entrypoints.h
@@ -17,6 +17,7 @@
 #ifndef ART_SRC_OAT_RUNTIME_OAT_SUPPORT_ENTRYPOINTS_H_
 #define ART_SRC_OAT_RUNTIME_OAT_SUPPORT_ENTRYPOINTS_H_
 
+#include "dex_file-inl.h"
 #include "runtime.h"
 
 #define ENTRYPOINT_OFFSET(x) \
@@ -30,6 +31,8 @@
 class Object;
 }  // namespace mirror
 class DvmDex;
+class MethodHelper;
+class ShadowFrame;
 class Thread;
 
 struct PACKED(4) EntryPoints {
@@ -104,6 +107,14 @@
   uint64_t (*pShrLong)(uint64_t, uint32_t);
   uint64_t (*pUshrLong)(uint64_t, uint32_t);
 
+  // Interpreter
+  void (*pInterpreterToInterpreterEntry)(Thread* self, MethodHelper& mh,
+                                         const DexFile::CodeItem* code_item,
+                                         ShadowFrame* shadow_frame, JValue* result);
+  void (*pInterpreterToQuickEntry)(Thread* self, MethodHelper& mh,
+                                   const DexFile::CodeItem* code_item,
+                                   ShadowFrame* shadow_frame, JValue* result);
+
   // Intrinsics
   int32_t (*pIndexOf)(void*, uint32_t, uint32_t, uint32_t);
   int32_t (*pMemcmp16)(void*, void*, int32_t);
@@ -111,6 +122,10 @@
   void* (*pMemcpy)(void*, const void*, size_t);
 
   // Invocation
+  const void* (*pPortableResolutionTrampolineFromCode)(mirror::AbstractMethod*, mirror::Object*,
+                                                       mirror::AbstractMethod**, Thread*);
+  const void* (*pQuickResolutionTrampolineFromCode)(mirror::AbstractMethod*, mirror::Object*,
+                                                    mirror::AbstractMethod**, Thread*);
   void (*pInvokeDirectTrampolineWithAccessCheck)(uint32_t, void*);
   void (*pInvokeInterfaceTrampoline)(uint32_t, void*);
   void (*pInvokeInterfaceTrampolineWithAccessCheck)(uint32_t, void*);
@@ -131,24 +146,25 @@
   void (*pThrowStackOverflowFromCode)(void*);
 };
 
+
 // JNI entrypoints.
 extern uint32_t JniMethodStart(Thread* self)
-    UNLOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot));
+    UNLOCK_FUNCTION(Locks::mutator_lock_) HOT_ATTR;
 extern uint32_t JniMethodStartSynchronized(jobject to_lock, Thread* self)
-    UNLOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot));
+    UNLOCK_FUNCTION(Locks::mutator_lock_) HOT_ATTR;
 extern void JniMethodEnd(uint32_t saved_local_ref_cookie, Thread* self)
-    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot));
+    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) HOT_ATTR;
 extern void JniMethodEndSynchronized(uint32_t saved_local_ref_cookie, jobject locked,
                                      Thread* self)
-    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot));
+    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) HOT_ATTR;
 extern mirror::Object* JniMethodEndWithReference(jobject result, uint32_t saved_local_ref_cookie,
                                                  Thread* self)
-    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot));
+    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) HOT_ATTR;
 
 extern mirror::Object* JniMethodEndWithReferenceSynchronized(jobject result,
                                                              uint32_t saved_local_ref_cookie,
                                                              jobject locked, Thread* self)
-    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot));
+    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) HOT_ATTR;
 
 // Initialize an entry point data structure.
 void InitEntryPoints(EntryPoints* points);
diff --git a/src/oat/runtime/support_field.cc b/src/oat/runtime/support_field.cc
index 5821063..c20326c 100644
--- a/src/oat/runtime/support_field.cc
+++ b/src/oat/runtime/support_field.cc
@@ -34,7 +34,7 @@
     return field->Get32(field->GetDeclaringClass());
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int32_t));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int32_t), true);
   if (LIKELY(field != NULL)) {
     return field->Get32(field->GetDeclaringClass());
   }
@@ -50,7 +50,7 @@
     return field->Get64(field->GetDeclaringClass());
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int64_t));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int64_t), true);
   if (LIKELY(field != NULL)) {
     return field->Get64(field->GetDeclaringClass());
   }
@@ -67,7 +67,7 @@
     return field->GetObj(field->GetDeclaringClass());
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, StaticObjectRead, sizeof(mirror::Object*));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticObjectRead, sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     return field->GetObj(field->GetDeclaringClass());
   }
@@ -83,7 +83,7 @@
     return field->Get32(obj);
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveRead, sizeof(int32_t));
+  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveRead, sizeof(int32_t), true);
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -104,7 +104,7 @@
     return field->Get64(obj);
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveRead, sizeof(int64_t));
+  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveRead, sizeof(int64_t), true);
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -126,7 +126,7 @@
     return field->GetObj(obj);
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, InstanceObjectRead, sizeof(mirror::Object*));
+  field = FindFieldFromCode(field_idx, referrer, self, InstanceObjectRead, sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -148,7 +148,7 @@
     return 0;  // success
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int32_t));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int32_t), true);
   if (LIKELY(field != NULL)) {
     field->Set32(field->GetDeclaringClass(), new_value);
     return 0;  // success
@@ -165,7 +165,7 @@
     return 0;  // success
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int64_t));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int64_t), true);
   if (LIKELY(field != NULL)) {
     field->Set64(field->GetDeclaringClass(), new_value);
     return 0;  // success
@@ -186,7 +186,7 @@
     }
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, StaticObjectWrite, sizeof(mirror::Object*));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticObjectWrite, sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     field->SetObj(field->GetDeclaringClass(), new_value);
     return 0;  // success
@@ -204,7 +204,7 @@
     return 0;  // success
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveWrite, sizeof(int32_t));
+  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveWrite, sizeof(int32_t), true);
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -231,7 +231,7 @@
   }
   *sp = callee_save;
   self->SetTopOfStack(sp, 0);
-  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveWrite, sizeof(int64_t));
+  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveWrite, sizeof(int64_t), true);
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -257,7 +257,7 @@
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode(field_idx, referrer, self, InstanceObjectWrite,
-                            sizeof(mirror::Object*));
+                            sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
diff --git a/src/oat/runtime/support_interpreter.cc b/src/oat/runtime/support_interpreter.cc
index a5d6fa3..55be54f 100644
--- a/src/oat/runtime/support_interpreter.cc
+++ b/src/oat/runtime/support_interpreter.cc
@@ -110,12 +110,11 @@
   return result.GetJ();
 }
 
-void artInterpreterToQuickEntry(Thread* self, ShadowFrame* shadow_frame, JValue* result)
+extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh,
+                                           const DexFile::CodeItem* code_item,
+                                           ShadowFrame* shadow_frame, JValue* result)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   mirror::AbstractMethod* method = shadow_frame->GetMethod();
-  MethodHelper mh(method);
-  const DexFile::CodeItem* code_item = mh.GetCodeItem();
-
   uint16_t arg_offset = (code_item == NULL) ? 0 : code_item->registers_size_ - code_item->ins_size_;
   ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
   arg_array.BuildArgArray(shadow_frame, arg_offset);
diff --git a/src/oat/runtime/support_invoke.cc b/src/oat/runtime/support_invoke.cc
index a96555d..6a95f3c 100644
--- a/src/oat/runtime/support_invoke.cc
+++ b/src/oat/runtime/support_invoke.cc
@@ -17,6 +17,7 @@
 #include "callee_save_frame.h"
 #include "dex_instruction-inl.h"
 #include "mirror/class-inl.h"
+#include "mirror/dex_cache-inl.h"
 #include "mirror/abstract_method-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
diff --git a/src/oat/runtime/support_stubs.cc b/src/oat/runtime/support_stubs.cc
index df2dda2..71b67d0 100644
--- a/src/oat/runtime/support_stubs.cc
+++ b/src/oat/runtime/support_stubs.cc
@@ -32,6 +32,7 @@
 
 // Lazily resolve a method for portable. Called by stub code.
 extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called,
+                                                       mirror::Object* receiver,
                                                        mirror::AbstractMethod** called_addr,
                                                        Thread* thread)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -79,6 +80,14 @@
         invoke_type = kVirtual;
         is_range = true;
         break;
+      case Instruction::INVOKE_INTERFACE:
+        invoke_type = kInterface;
+        is_range = false;
+        break;
+      case Instruction::INVOKE_INTERFACE_RANGE:
+        invoke_type = kInterface;
+        is_range = true;
+        break;
       default:
         LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL);
         // Avoid used uninitialized warnings.
@@ -87,6 +96,12 @@
     }
     uint32_t dex_method_idx = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c();
     called = linker->ResolveMethod(dex_method_idx, caller, invoke_type);
+    // Refine called method based on receiver.
+    if (invoke_type == kVirtual) {
+      called = receiver->GetClass()->FindVirtualMethodForVirtual(called);
+    } else if (invoke_type == kInterface) {
+      called = receiver->GetClass()->FindVirtualMethodForInterface(called);
+    }
   } else {
     CHECK(called->IsStatic()) << PrettyMethod(called);
     invoke_type = kStatic;
@@ -129,7 +144,7 @@
     // Expect class to at least be initializing.
     DCHECK(called->GetDeclaringClass()->IsInitializing());
     // Don't want infinite recursion.
-    DCHECK(code != GetResolutionTrampoline());
+    DCHECK(code != GetResolutionTrampoline(linker));
     // Set up entry into main method
     *called_addr = called;
   }
@@ -138,6 +153,7 @@
 
 // Lazily resolve a method for quick. Called by stub code.
 extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* called,
+                                                    mirror::Object* receiver,
                                                     mirror::AbstractMethod** sp, Thread* thread)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
 #if defined(__arm__)
@@ -261,6 +277,14 @@
         invoke_type = kVirtual;
         is_range = true;
         break;
+      case Instruction::INVOKE_INTERFACE:
+        invoke_type = kInterface;
+        is_range = false;
+        break;
+      case Instruction::INVOKE_INTERFACE_RANGE:
+        invoke_type = kInterface;
+        is_range = true;
+        break;
       default:
         LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL);
         // Avoid used uninitialized warnings.
@@ -334,6 +358,12 @@
   if (LIKELY(!thread->IsExceptionPending())) {
     // Incompatible class change should have been handled in resolve method.
     CHECK(!called->CheckIncompatibleClassChange(invoke_type));
+    // Refine called method based on receiver.
+    if (invoke_type == kVirtual) {
+      called = receiver->GetClass()->FindVirtualMethodForVirtual(called);
+    } else if (invoke_type == kInterface) {
+      called = receiver->GetClass()->FindVirtualMethodForInterface(called);
+    }
     // Ensure that the called method's class is initialized.
     mirror::Class* called_class = called->GetDeclaringClass();
     linker->EnsureInitialized(called_class, true, true);
@@ -363,7 +393,7 @@
     // Expect class to at least be initializing.
     DCHECK(called->GetDeclaringClass()->IsInitializing());
     // Don't want infinite recursion.
-    DCHECK(code != GetResolutionTrampoline());
+    DCHECK(code != GetResolutionTrampoline(linker));
     // Set up entry into main method
     regs[0] = reinterpret_cast<uintptr_t>(called);
   }
diff --git a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
index 357bbe0..a90a583 100644
--- a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
+++ b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
@@ -75,6 +75,14 @@
 extern "C" uint64_t art_quick_lshr_from_code(uint64_t, uint32_t);
 extern "C" uint64_t art_quick_lushr_from_code(uint64_t, uint32_t);
 
+// Interpreter entrypoints.
+extern "C" void artInterpreterToInterpreterEntry(Thread* self, MethodHelper& mh,
+                                                 const DexFile::CodeItem* code_item,
+                                                 ShadowFrame* shadow_frame, JValue* result);
+extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh,
+                                           const DexFile::CodeItem* code_item,
+                                           ShadowFrame* shadow_frame, JValue* result);
+
 // Intrinsic entrypoints.
 extern "C" int32_t art_quick_memcmp16(void*, void*, int32_t);
 extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t);
@@ -82,6 +90,12 @@
 extern "C" void* art_quick_memcpy(void*, const void*, size_t);
 
 // Invoke entrypoints.
+extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called,
+                                                       mirror::Object* receiver,
+                                                       mirror::AbstractMethod** sp, Thread* thread);
+extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* called,
+                                                    mirror::Object* receiver,
+                                                    mirror::AbstractMethod** sp, Thread* thread);
 extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*);
 extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*);
 extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*);
@@ -171,6 +185,10 @@
   points->pShrLong = art_quick_lshr_from_code;
   points->pUshrLong = art_quick_lushr_from_code;
 
+  // Interpreter
+  points->pInterpreterToInterpreterEntry = artInterpreterToInterpreterEntry;
+  points->pInterpreterToQuickEntry = artInterpreterToQuickEntry;
+
   // Intrinsics
   points->pIndexOf = art_quick_indexof;
   points->pMemcmp16 = art_quick_memcmp16;
@@ -178,6 +196,8 @@
   points->pMemcpy = art_quick_memcpy;
 
   // Invocation
+  points->pPortableResolutionTrampolineFromCode = artPortableResolutionTrampoline;
+  points->pQuickResolutionTrampolineFromCode = artQuickResolutionTrampoline;
   points->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check;
   points->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline;
   points->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check;
diff --git a/src/oat/runtime/x86/runtime_support_x86.S b/src/oat/runtime/x86/runtime_support_x86.S
index d3a1fb7..ee6db0c 100644
--- a/src/oat/runtime/x86/runtime_support_x86.S
+++ b/src/oat/runtime/x86/runtime_support_x86.S
@@ -301,55 +301,6 @@
 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.
-     */
-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
-    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
-    PUSH edx                      // pass called method* address
-    PUSH eax                      // pass method*
-    call SYMBOL(artPortableResolutionTrampoline)  // (method_idx, sp, Thread*)
-    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
-resolve_fail:
-    ret
-END_FUNCTION art_portable_resolution_trampoline
-
-    /*
-     * Quick resolution trampoline.
-     */
-DEFINE_FUNCTION art_quick_resolution_trampoline
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    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
-    POP ebx
-    POP ebp
-    POP esi
-    xchgl %edi, (%esp)            // swap %edi and code pointer
-    ret                           // tail call to intended method
-END_FUNCTION art_quick_resolution_trampoline
-
     /*
      * Portable invocation stub.
      * On entry:
diff --git a/src/oat_test.cc b/src/oat_test.cc
index dd336d9..29e2891 100644
--- a/src/oat_test.cc
+++ b/src/oat_test.cc
@@ -68,16 +68,16 @@
   const bool compile = false;  // DISABLED_ due to the time to compile libcore
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
 
+  // TODO: make selectable
+#if defined(ART_USE_PORTABLE_COMPILER)
+  CompilerBackend compiler_backend = kPortable;
+#else
+  CompilerBackend compiler_backend = kQuick;
+#endif
+  compiler_driver_.reset(new CompilerDriver(compiler_backend, kThumb2, false, NULL, 2, false,
+                                            true, true));
   jobject class_loader = NULL;
   if (compile) {
-    // TODO: make selectable
-#if defined(ART_USE_PORTABLE_COMPILER)
-    CompilerBackend compiler_backend = kPortable;
-#else
-    CompilerBackend compiler_backend = kQuick;
-#endif
-    compiler_driver_.reset(new CompilerDriver(compiler_backend, kThumb2, false, 2, false,
-                                              NULL, true, true));
     compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath());
   }
 
@@ -143,7 +143,7 @@
 TEST_F(OatTest, OatHeaderSizeCheck) {
   // If this test is failing and you have to update these constants,
   // it is time to update OatHeader::kOatVersion
-  EXPECT_EQ(36U, sizeof(OatHeader));
+  EXPECT_EQ(52U, sizeof(OatHeader));
   EXPECT_EQ(28U, sizeof(OatMethodOffsets));
 }
 
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index 8acbfe9..639d249 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -54,13 +54,35 @@
                      uint32_t image_file_location_oat_begin,
                      const std::string& image_file_location,
                      const CompilerDriver* compiler)
-    : compiler_driver_(compiler) {
-  image_file_location_oat_checksum_ = image_file_location_oat_checksum;
-  image_file_location_oat_begin_ = image_file_location_oat_begin;
-  image_file_location_ = image_file_location;
-  dex_files_ = &dex_files;
-  oat_header_ = NULL;
-  executable_offset_padding_length_ = 0;
+  : compiler_driver_(compiler),
+    dex_files_(&dex_files),
+    image_file_location_oat_checksum_(image_file_location_oat_checksum),
+    image_file_location_oat_begin_(image_file_location_oat_begin),
+    image_file_location_(image_file_location),
+    oat_header_(NULL),
+    size_dex_file_alignment_(0),
+    size_executable_offset_alignment_(0),
+    size_oat_header_(0),
+    size_oat_header_image_file_location_(0),
+    size_dex_file_(0),
+    size_interpreter_to_interpreter_entry_(0),
+    size_interpreter_to_quick_entry_(0),
+    size_portable_resolution_trampoline_(0),
+    size_quick_resolution_trampoline_(0),
+    size_stubs_alignment_(0),
+    size_code_size_(0),
+    size_code_(0),
+    size_code_alignment_(0),
+    size_mapping_table_(0),
+    size_vmap_table_(0),
+    size_gc_map_(0),
+    size_oat_dex_file_location_size_(0),
+    size_oat_dex_file_location_data_(0),
+    size_oat_dex_file_location_checksum_(0),
+    size_oat_dex_file_offset_(0),
+    size_oat_dex_file_methods_offsets_(0),
+    size_oat_class_status_(0),
+    size_oat_class_method_offsets_(0) {
 
   size_t offset = InitOatHeader();
   offset = InitOatDexFiles(offset);
@@ -70,6 +92,7 @@
   offset = InitOatCodeDexFiles(offset);
 
   CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
+  CHECK(image_file_location.empty() == compiler->IsImage());
 }
 
 OatWriter::~OatWriter() {
@@ -106,7 +129,9 @@
   // calculate the offsets within OatDexFiles to the DexFiles
   for (size_t i = 0; i != dex_files_->size(); ++i) {
     // dex files are required to be 4 byte aligned
+    size_t original_offset = offset;
     offset = RoundUp(offset, 4);
+    size_dex_file_alignment_ += offset - original_offset;
 
     // set offset in OatDexFile to DexFile
     oat_dex_files_[i]->dex_file_offset_ = offset;
@@ -162,7 +187,33 @@
   // required to be on a new page boundary
   offset = RoundUp(offset, kPageSize);
   oat_header_->SetExecutableOffset(offset);
-  executable_offset_padding_length_ = offset - old_offset;
+  size_executable_offset_alignment_ = offset - old_offset;
+  if (compiler_driver_->IsImage()) {
+    InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
+    oat_header_->SetInterpreterToInterpreterEntryOffset(offset);
+    interpreter_to_interpreter_entry_.reset(compiler_driver_->CreateInterpreterToInterpreterEntry());
+    offset += interpreter_to_interpreter_entry_->size();
+
+    offset = CompiledCode::AlignCode(offset, instruction_set);
+    oat_header_->SetInterpreterToQuickEntryOffset(offset);
+    interpreter_to_quick_entry_.reset(compiler_driver_->CreateInterpreterToQuickEntry());
+    offset += interpreter_to_quick_entry_->size();
+
+    offset = CompiledCode::AlignCode(offset, instruction_set);
+    oat_header_->SetPortableResolutionTrampolineOffset(offset);
+    portable_resolution_trampoline_.reset(compiler_driver_->CreatePortableResolutionTrampoline());
+    offset += portable_resolution_trampoline_->size();
+
+    offset = CompiledCode::AlignCode(offset, instruction_set);
+    oat_header_->SetQuickResolutionTrampolineOffset(offset);
+    quick_resolution_trampoline_.reset(compiler_driver_->CreateQuickResolutionTrampoline());
+    offset += quick_resolution_trampoline_->size();
+  } else {
+    oat_header_->SetInterpreterToInterpreterEntryOffset(0);
+    oat_header_->SetInterpreterToQuickEntryOffset(0);
+    oat_header_->SetPortableResolutionTrampolineOffset(0);
+    oat_header_->SetQuickResolutionTrampolineOffset(0);
+  }
   return offset;
 }
 
@@ -389,11 +440,13 @@
     PLOG(ERROR) << "Failed to write oat header to " << out.GetLocation();
     return false;
   }
+  size_oat_header_ += sizeof(*oat_header_);
 
   if (!out.WriteFully(image_file_location_.data(), image_file_location_.size())) {
     PLOG(ERROR) << "Failed to write oat header image file location to " << out.GetLocation();
     return false;
   }
+  size_oat_header_image_file_location_ += image_file_location_.size();
 
   if (!WriteTables(out)) {
     LOG(ERROR) << "Failed to write oat tables to " << out.GetLocation();
@@ -412,12 +465,47 @@
     return false;
   }
 
+  if (kIsDebugBuild) {
+    uint32_t size_total = 0;
+    #define DO_STAT(x) \
+      LOG(INFO) << #x "=" << PrettySize(x) << " (" << x << "B)"; \
+      size_total += x;
+
+    DO_STAT(size_dex_file_alignment_);
+    DO_STAT(size_executable_offset_alignment_);
+    DO_STAT(size_oat_header_);
+    DO_STAT(size_oat_header_image_file_location_);
+    DO_STAT(size_dex_file_);
+    DO_STAT(size_interpreter_to_interpreter_entry_);
+    DO_STAT(size_interpreter_to_quick_entry_);
+    DO_STAT(size_portable_resolution_trampoline_);
+    DO_STAT(size_quick_resolution_trampoline_);
+    DO_STAT(size_stubs_alignment_);
+    DO_STAT(size_code_size_);
+    DO_STAT(size_code_);
+    DO_STAT(size_code_alignment_);
+    DO_STAT(size_mapping_table_);
+    DO_STAT(size_vmap_table_);
+    DO_STAT(size_gc_map_);
+    DO_STAT(size_oat_dex_file_location_size_);
+    DO_STAT(size_oat_dex_file_location_data_);
+    DO_STAT(size_oat_dex_file_location_checksum_);
+    DO_STAT(size_oat_dex_file_offset_);
+    DO_STAT(size_oat_dex_file_methods_offsets_);
+    DO_STAT(size_oat_class_status_);
+    DO_STAT(size_oat_class_method_offsets_);
+    #undef DO_STAT
+
+    LOG(INFO) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)"; \
+    CHECK_EQ(size_total, static_cast<uint32_t>(out.Seek(0, kSeekCurrent)));
+  }
+
   return true;
 }
 
 bool OatWriter::WriteTables(OutputStream& out) {
   for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
-    if (!oat_dex_files_[i]->Write(out)) {
+    if (!oat_dex_files_[i]->Write(this, out)) {
       PLOG(ERROR) << "Failed to write oat dex information to " << out.GetLocation();
       return false;
     }
@@ -436,9 +524,10 @@
       PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation() << " to " << out.GetLocation();
       return false;
     }
+    size_dex_file_ += dex_file->GetHeader().file_size_;
   }
   for (size_t i = 0; i != oat_classes_.size(); ++i) {
-    if (!oat_classes_[i]->Write(out)) {
+    if (!oat_classes_[i]->Write(this, out)) {
       PLOG(ERROR) << "Failed to write oat methods information to " << out.GetLocation();
       return false;
     }
@@ -448,13 +537,59 @@
 
 size_t OatWriter::WriteCode(OutputStream& out) {
   uint32_t offset = oat_header_->GetExecutableOffset();
-  off_t new_offset = out.Seek(executable_offset_padding_length_, kSeekCurrent);
+  off_t new_offset = out.Seek(size_executable_offset_alignment_, kSeekCurrent);
   if (static_cast<uint32_t>(new_offset) != offset) {
     PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
                 << " Expected: " << offset << " File: " << out.GetLocation();
     return 0;
   }
   DCHECK_OFFSET();
+  if (compiler_driver_->IsImage()) {
+    InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
+    if (!out.WriteFully(&(*interpreter_to_interpreter_entry_)[0], interpreter_to_interpreter_entry_->size())) {
+      PLOG(ERROR) << "Failed to write interpreter to interpreter entry to " << out.GetLocation();
+      return false;
+    }
+    size_interpreter_to_interpreter_entry_ += interpreter_to_interpreter_entry_->size();
+    offset += interpreter_to_interpreter_entry_->size();
+    DCHECK_OFFSET();
+
+    uint32_t aligned_offset = CompiledCode::AlignCode(offset, instruction_set);
+    uint32_t alignment_padding = aligned_offset - offset;
+    out.Seek(alignment_padding, kSeekCurrent);
+    size_stubs_alignment_ += alignment_padding;
+    if (!out.WriteFully(&(*interpreter_to_quick_entry_)[0], interpreter_to_quick_entry_->size())) {
+      PLOG(ERROR) << "Failed to write interpreter to quick entry to " << out.GetLocation();
+      return false;
+    }
+    size_interpreter_to_quick_entry_ += interpreter_to_quick_entry_->size();
+    offset += alignment_padding + interpreter_to_quick_entry_->size();
+    DCHECK_OFFSET();
+
+    aligned_offset = CompiledCode::AlignCode(offset, instruction_set);
+    alignment_padding = aligned_offset - offset;
+    out.Seek(alignment_padding, kSeekCurrent);
+    size_stubs_alignment_ += alignment_padding;
+    if (!out.WriteFully(&(*portable_resolution_trampoline_)[0], portable_resolution_trampoline_->size())) {
+      PLOG(ERROR) << "Failed to write portable resolution trampoline to " << out.GetLocation();
+      return false;
+    }
+    size_portable_resolution_trampoline_ += portable_resolution_trampoline_->size();
+    offset += alignment_padding + portable_resolution_trampoline_->size();
+    DCHECK_OFFSET();
+
+    aligned_offset = CompiledCode::AlignCode(offset, instruction_set);
+    alignment_padding = aligned_offset - offset;
+    out.Seek(alignment_padding, kSeekCurrent);
+    size_stubs_alignment_ += alignment_padding;
+    if (!out.WriteFully(&(*quick_resolution_trampoline_)[0], quick_resolution_trampoline_->size())) {
+      PLOG(ERROR) << "Failed to write quick resolution trampoline to " << out.GetLocation();
+      return false;
+    }
+    size_quick_resolution_trampoline_ += quick_resolution_trampoline_->size();
+    offset += alignment_padding + quick_resolution_trampoline_->size();
+    DCHECK_OFFSET();
+  }
   return offset;
 }
 
@@ -547,6 +682,7 @@
     uint32_t aligned_code_delta = aligned_offset - offset;
     if (aligned_code_delta != 0) {
       off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent);
+      size_code_alignment_ += aligned_code_delta;
       if (static_cast<uint32_t>(new_offset) != aligned_offset) {
         PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
                     << " Expected: " << aligned_offset << " File: " << out.GetLocation();
@@ -572,12 +708,14 @@
         ReportWriteFailure("method code size", method_idx, dex_file, out);
         return 0;
       }
+      size_code_size_ += sizeof(code_size);
       offset += sizeof(code_size);
       DCHECK_OFFSET();
       if (!out.WriteFully(&code[0], code_size)) {
         ReportWriteFailure("method code", method_idx, dex_file, out);
         return 0;
       }
+      size_code_ += code_size;
       offset += code_size;
     }
     DCHECK_OFFSET();
@@ -602,6 +740,7 @@
         ReportWriteFailure("mapping table", method_idx, dex_file, out);
         return 0;
       }
+      size_mapping_table_ += mapping_table_size;
       offset += mapping_table_size;
     }
     DCHECK_OFFSET();
@@ -625,6 +764,7 @@
         ReportWriteFailure("vmap table", method_idx, dex_file, out);
         return 0;
       }
+      size_vmap_table_ += vmap_table_size;
       offset += vmap_table_size;
     }
     DCHECK_OFFSET();
@@ -648,6 +788,7 @@
         ReportWriteFailure("GC map", method_idx, dex_file, out);
         return 0;
       }
+      size_gc_map_ += gc_map_size;
       offset += gc_map_size;
     }
     DCHECK_OFFSET();
@@ -683,29 +824,35 @@
                             sizeof(methods_offsets_[0]) * methods_offsets_.size());
 }
 
-bool OatWriter::OatDexFile::Write(OutputStream& out) const {
+bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream& out) const {
   DCHECK_OFFSET_();
   if (!out.WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
     PLOG(ERROR) << "Failed to write dex file location length to " << out.GetLocation();
     return false;
   }
+  oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_);
   if (!out.WriteFully(dex_file_location_data_, dex_file_location_size_)) {
     PLOG(ERROR) << "Failed to write dex file location data to " << out.GetLocation();
     return false;
   }
+  oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_;
   if (!out.WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
     PLOG(ERROR) << "Failed to write dex file location checksum to " << out.GetLocation();
     return false;
   }
+  oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_);
   if (!out.WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
     PLOG(ERROR) << "Failed to write dex file offset to " << out.GetLocation();
     return false;
   }
+  oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_);
   if (!out.WriteFully(&methods_offsets_[0],
                       sizeof(methods_offsets_[0]) * methods_offsets_.size())) {
     PLOG(ERROR) << "Failed to write methods offsets to " << out.GetLocation();
     return false;
   }
+  oat_writer->size_oat_dex_file_methods_offsets_ +=
+      sizeof(methods_offsets_[0]) * methods_offsets_.size();
   return true;
 }
 
@@ -736,12 +883,13 @@
                             sizeof(method_offsets_[0]) * method_offsets_.size());
 }
 
-bool OatWriter::OatClass::Write(OutputStream& out) const {
+bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream& out) const {
   DCHECK_OFFSET_();
   if (!out.WriteFully(&status_, sizeof(status_))) {
     PLOG(ERROR) << "Failed to write class status to " << out.GetLocation();
     return false;
   }
+  oat_writer->size_oat_class_status_ += sizeof(status_);
   DCHECK_EQ(static_cast<off_t>(GetOatMethodOffsetsOffsetFromOatHeader(0)),
             out.Seek(0, kSeekCurrent));
   if (!out.WriteFully(&method_offsets_[0],
@@ -749,6 +897,7 @@
     PLOG(ERROR) << "Failed to write method offsets to " << out.GetLocation();
     return false;
   }
+  oat_writer->size_oat_class_method_offsets_ += sizeof(method_offsets_[0]) * method_offsets_.size();
   DCHECK_EQ(static_cast<off_t>(GetOatMethodOffsetsOffsetFromOatHeader(method_offsets_.size())),
             out.Seek(0, kSeekCurrent));
   return true;
diff --git a/src/oat_writer.h b/src/oat_writer.h
index e1d76f4..b201d6b 100644
--- a/src/oat_writer.h
+++ b/src/oat_writer.h
@@ -83,7 +83,8 @@
   size_t InitOatDexFiles(size_t offset);
   size_t InitDexFiles(size_t offset);
   size_t InitOatClasses(size_t offset);
-  size_t InitOatCode(size_t offset);
+  size_t InitOatCode(size_t offset)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   size_t InitOatCodeDexFiles(size_t offset)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   size_t InitOatCodeDexFile(size_t offset,
@@ -120,7 +121,7 @@
     explicit OatDexFile(size_t offset, const DexFile& dex_file);
     size_t SizeOf() const;
     void UpdateChecksum(OatHeader& oat_header) const;
-    bool Write(OutputStream& out) const;
+    bool Write(OatWriter* oat_writer, OutputStream& out) const;
 
     // Offset of start of OatDexFile from beginning of OatHeader. It is
     // used to validate file position when writing.
@@ -144,7 +145,7 @@
     size_t GetOatMethodOffsetsOffsetFromOatClass(size_t class_def_method_index_) const;
     size_t SizeOf() const;
     void UpdateChecksum(OatHeader& oat_header) const;
-    bool Write(OutputStream& out) const;
+    bool Write(OatWriter* oat_writer, OutputStream& out) const;
 
     // Offset of start of OatClass from beginning of OatHeader. It is
     // used to validate file position when writing. For Portable, it
@@ -175,7 +176,35 @@
   OatHeader* oat_header_;
   std::vector<OatDexFile*> oat_dex_files_;
   std::vector<OatClass*> oat_classes_;
-  uint32_t executable_offset_padding_length_;
+  UniquePtr<const std::vector<uint8_t> > interpreter_to_interpreter_entry_;
+  UniquePtr<const std::vector<uint8_t> > interpreter_to_quick_entry_;
+  UniquePtr<const std::vector<uint8_t> > portable_resolution_trampoline_;
+  UniquePtr<const std::vector<uint8_t> > quick_resolution_trampoline_;
+
+  // output stats
+  uint32_t size_dex_file_alignment_;
+  uint32_t size_executable_offset_alignment_;
+  uint32_t size_oat_header_;
+  uint32_t size_oat_header_image_file_location_;
+  uint32_t size_dex_file_;
+  uint32_t size_interpreter_to_interpreter_entry_;
+  uint32_t size_interpreter_to_quick_entry_;
+  uint32_t size_portable_resolution_trampoline_;
+  uint32_t size_quick_resolution_trampoline_;
+  uint32_t size_stubs_alignment_;
+  uint32_t size_code_size_;
+  uint32_t size_code_;
+  uint32_t size_code_alignment_;
+  uint32_t size_mapping_table_;
+  uint32_t size_vmap_table_;
+  uint32_t size_gc_map_;
+  uint32_t size_oat_dex_file_location_size_;
+  uint32_t size_oat_dex_file_location_data_;
+  uint32_t size_oat_dex_file_location_checksum_;
+  uint32_t size_oat_dex_file_offset_;
+  uint32_t size_oat_dex_file_methods_offsets_;
+  uint32_t size_oat_class_status_;
+  uint32_t size_oat_class_method_offsets_;
 
   template <class T> struct MapCompare {
    public:
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 7a99f8d..a8a0e86 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -853,7 +853,13 @@
       if (value == NULL) {
         os << StringPrintf("null   %s\n", PrettyDescriptor(descriptor).c_str());
       } else {
-        PrettyObjectValue(os, fh.GetType(), value);
+        // Grab the field type without causing resolution.
+        mirror::Class* field_type = fh.GetType(false);
+        if (field_type != NULL) {
+          PrettyObjectValue(os, field_type, value);
+        } else {
+          os << StringPrintf("%p   %s\n", value, PrettyDescriptor(descriptor).c_str());
+        }
       }
     }
   }
@@ -880,7 +886,7 @@
   const void* GetOatCodeBegin(mirror::AbstractMethod* m)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     const void* code = m->GetEntryPointFromCompiledCode();
-    if (code == GetResolutionTrampoline()) {
+    if (code == GetResolutionTrampoline(Runtime::Current()->GetClassLinker())) {
       code = oat_dumper_->GetOatCode(m);
     }
     if (oat_dumper_->GetInstructionSet() == kThumb2) {
diff --git a/src/object_utils.h b/src/object_utils.h
index 6c6f60b..6a07425 100644
--- a/src/object_utils.h
+++ b/src/object_utils.h
@@ -282,13 +282,13 @@
       return field_index == 0 ? "interfaces" : "throws";
     }
   }
-  mirror::Class* GetType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  mirror::Class* GetType(bool resolve = true) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     uint32_t field_index = field_->GetDexFieldIndex();
     if (!field_->GetDeclaringClass()->IsProxyClass()) {
       const DexFile& dex_file = GetDexFile();
       const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index);
       mirror::Class* type = GetDexCache()->GetResolvedType(field_id.type_idx_);
-      if (type == NULL) {
+      if (resolve && (type == NULL)) {
         type = GetClassLinker()->ResolveType(field_id.type_idx_, field_);
         CHECK(type != NULL || Thread::Current()->IsExceptionPending());
       }
diff --git a/src/output_stream_test.cc b/src/output_stream_test.cc
index 0e02825..c9e0ede 100644
--- a/src/output_stream_test.cc
+++ b/src/output_stream_test.cc
@@ -25,7 +25,7 @@
  protected:
   void CheckOffset(off_t expected) {
     off_t actual = output_stream_->Seek(0, kSeekCurrent);
-    CHECK_EQ(expected, actual);
+    EXPECT_EQ(expected, actual);
   }
 
   void SetOutputStream(OutputStream& output_stream) {
@@ -33,16 +33,16 @@
   }
 
   void GenerateTestOutput() {
-    CHECK_EQ(3, output_stream_->Seek(3, kSeekCurrent));
+    EXPECT_EQ(3, output_stream_->Seek(3, kSeekCurrent));
     CheckOffset(3);
-    CHECK_EQ(2, output_stream_->Seek(2, kSeekSet));
+    EXPECT_EQ(2, output_stream_->Seek(2, kSeekSet));
     CheckOffset(2);
     uint8_t buf[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
-    CHECK(output_stream_->WriteFully(buf, 2));
+    EXPECT_TRUE(output_stream_->WriteFully(buf, 2));
     CheckOffset(4);
-    CHECK_EQ(6, output_stream_->Seek(2, kSeekEnd));
+    EXPECT_EQ(6, output_stream_->Seek(2, kSeekEnd));
     CheckOffset(6);
-    CHECK(output_stream_->WriteFully(buf, 4));
+    EXPECT_TRUE(output_stream_->WriteFully(buf, 4));
     CheckOffset(10);
   }
 
@@ -50,8 +50,8 @@
     uint8_t expected[] = {
         0, 0, 1, 2, 0, 0, 1, 2, 3, 4
     };
-    CHECK_EQ(sizeof(expected), actual.size());
-    CHECK_EQ(0, memcmp(expected, &actual[0], actual.size()));
+    EXPECT_EQ(sizeof(expected), actual.size());
+    EXPECT_EQ(0, memcmp(expected, &actual[0], actual.size()));
   }
 
   OutputStream* output_stream_;
@@ -63,10 +63,10 @@
   SetOutputStream(output_stream);
   GenerateTestOutput();
   UniquePtr<File> in(OS::OpenFile(tmp.GetFilename().c_str(), false));
-  CHECK(in.get() != NULL);
+  EXPECT_TRUE(in.get() != NULL);
   std::vector<uint8_t> actual(in->GetLength());
   bool readSuccess = in->ReadFully(&actual[0], actual.size());
-  CHECK(readSuccess);
+  EXPECT_TRUE(readSuccess);
   CheckTestOutput(actual);
 }
 
diff --git a/src/runtime.cc b/src/runtime.cc
index 186f208..87456ca 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -210,29 +210,18 @@
     LOG(INTERNAL_FATAL) << "Unexpectedly returned from abort hook!";
   }
 
-#if defined(__BIONIC__)
-  // TODO: finish merging patches to fix abort(3) in bionic, then lose this!
-  // Bionic doesn't implement POSIX semantics for abort(3) in a multi-threaded
-  // process, so if we call abort(3) on a device, all threads in the process
-  // receive SIGABRT.  debuggerd dumps the stack trace of the main
-  // thread, whether or not that was the thread that failed.  By
-  // stuffing a value into a bogus address, we cause a segmentation
-  // fault in the current thread, and get a useful log from debuggerd.
-  // We can also trivially tell the difference between a crash and
-  // a deliberate abort by looking at the fault address.
-  *reinterpret_cast<char*>(0xdeadd00d) = 38;
-#elif defined(__APPLE__)
-  // TODO: check that this actually gives good stack traces on the Mac!
-  pthread_kill(pthread_self(), SIGABRT);
-#else
+#if defined(__GLIBC__)
   // TODO: we ought to be able to use pthread_kill(3) here (or abort(3),
   // which POSIX defines in terms of raise(3), which POSIX defines in terms
   // of pthread_kill(3)). On Linux, though, libcorkscrew can't unwind through
   // libpthread, which means the stacks we dump would be useless. Calling
   // tgkill(2) directly avoids that.
   syscall(__NR_tgkill, getpid(), GetTid(), SIGABRT);
-  // TODO: LLVM installs it's own SIGABRT handler so exit to be safe... Can we disable that?
+  // TODO: LLVM installs it's own SIGABRT handler so exit to be safe... Can we disable that in LLVM?
+  // If not, we could use sigaction(3) before calling tgkill(2) and lose this call to exit(3).
   exit(1);
+#else
+  abort();
 #endif
   // notreached
 }
@@ -1109,7 +1098,9 @@
   // TODO: use a special method for resolution method saves
   method->SetDexMethodIndex(DexFile::kDexNoIndex16);
   // When compiling, the code pointer will get set later when the image is loaded.
-  method->SetEntryPointFromCompiledCode(Runtime::Current()->IsCompiler() ? NULL : GetResolutionTrampoline());
+  Runtime* r = Runtime::Current();
+  ClassLinker* cl = r->GetClassLinker();
+  method->SetEntryPointFromCompiledCode(r->IsCompiler() ? NULL : GetResolutionTrampoline(cl));
   return method.get();
 }
 
diff --git a/src/runtime.h b/src/runtime.h
index 6f03fe0..1b0c437 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -63,11 +63,13 @@
 
   // In small mode, apps with fewer than this number of methods will be compiled 
   // anyways.
+  // TODO: come up with a reasonable default.
   static const size_t kDefaultSmallModeMethodThreshold = 0;
 
   // In small mode, methods smaller than this dex op count limit will get compiled
   // anyways.
-  static const size_t kDefaultSmallModeMethodDexSizeLimit = 0;
+  // TODO: come up with a reasonable default.
+  static const size_t kDefaultSmallModeMethodDexSizeLimit = 300;
 
   class ParsedOptions {
    public:
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 9242c87..f6225ed 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -142,7 +142,8 @@
 }
 
 mirror::Field* FindFieldFromCode(uint32_t field_idx, const mirror::AbstractMethod* referrer,
-                                 Thread* self, FindFieldType type, size_t expected_size) {
+                                 Thread* self, FindFieldType type, size_t expected_size,
+                                 bool access_check) {
   bool is_primitive;
   bool is_set;
   bool is_static;
@@ -162,12 +163,13 @@
   if (UNLIKELY(resolved_field == NULL)) {
     DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
     return NULL;  // Failure.
-  } else {
+  }
+  mirror::Class* fields_class = resolved_field->GetDeclaringClass();
+  if (access_check) {
     if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
       ThrowIncompatibleClassChangeErrorField(resolved_field, is_static, referrer);
       return NULL;
     }
-    mirror::Class* fields_class = resolved_field->GetDeclaringClass();
     mirror::Class* referring_class = referrer->GetDeclaringClass();
     if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
                  !referring_class->CanAccessMember(fields_class,
@@ -203,23 +205,24 @@
                                  is_primitive ? "primitive" : "non-primitive",
                                  PrettyField(resolved_field, true).c_str());
         return NULL;  // failure
-      } else if (!is_static) {
-        // instance fields must be being accessed on an initialized class
-        return resolved_field;
-      } else {
-        // If the class is initialized we're done.
-        if (fields_class->IsInitialized()) {
-          return resolved_field;
-        } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true, true)) {
-          // Otherwise let's ensure the class is initialized before resolving the field.
-          return resolved_field;
-        } else {
-          DCHECK(self->IsExceptionPending());  // Throw exception and unwind
-          return NULL;  // failure
-        }
       }
     }
   }
+  if (!is_static) {
+    // instance fields must be being accessed on an initialized class
+    return resolved_field;
+  } else {
+    // If the class is initialized we're done.
+    if (fields_class->IsInitialized()) {
+      return resolved_field;
+    } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true, true)) {
+      // Otherwise let's ensure the class is initialized before resolving the field.
+      return resolved_field;
+    } else {
+      DCHECK(self->IsExceptionPending());  // Throw exception and unwind
+      return NULL;  // failure
+    }
+  }
 }
 
 // Slow path method resolution
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 5fc8da5..0cb82a5 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -34,14 +34,12 @@
 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();
 extern "C" void art_quick_interpreter_entry(void*);
 extern "C" void art_quick_proxy_invoke_handler();
-extern "C" void art_quick_resolution_trampoline();
 extern "C" void art_work_around_app_jni_bugs();
 
 extern "C" double art_l2d(int64_t l);
@@ -146,7 +144,8 @@
 
 // Slow field find that can initialize classes and may throw exceptions.
 extern mirror::Field* FindFieldFromCode(uint32_t field_idx, const mirror::AbstractMethod* referrer,
-                                        Thread* self, FindFieldType type, size_t expected_size)
+                                        Thread* self, FindFieldType type, size_t expected_size,
+                                        bool access_check)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 // Fast path field resolution that can't initialize classes or throw exceptions.
@@ -373,22 +372,20 @@
   return reinterpret_cast<void*>(art_quick_interpreter_entry);
 }
 
-// Return address of portable resolution trampoline stub.
-static inline void* GetPortableResolutionTrampoline() {
-  return reinterpret_cast<void*>(art_portable_resolution_trampoline);
+static inline const void* GetPortableResolutionTrampoline(ClassLinker* class_linker) {
+  return class_linker->GetPortableResolutionTrampoline();
 }
 
-// Return address of quick resolution trampoline stub.
-static inline void* GetQuickResolutionTrampoline() {
-  return reinterpret_cast<void*>(art_quick_resolution_trampoline);
+static inline const void* GetQuickResolutionTrampoline(ClassLinker* class_linker) {
+  return class_linker->GetQuickResolutionTrampoline();
 }
 
 // Return address of resolution trampoline stub for defined compiler.
-static inline void* GetResolutionTrampoline() {
+static inline const void* GetResolutionTrampoline(ClassLinker* class_linker) {
 #if defined(ART_USE_PORTABLE_COMPILER)
-  return GetPortableResolutionTrampoline();
+  return GetPortableResolutionTrampoline(class_linker);
 #else
-  return GetQuickResolutionTrampoline();
+  return GetQuickResolutionTrampoline(class_linker);
 #endif
 }
 
diff --git a/src/stack.cc b/src/stack.cc
index 8690a36..8672975 100644
--- a/src/stack.cc
+++ b/src/stack.cc
@@ -42,6 +42,15 @@
   }
 }
 
+mirror::Object* ShadowFrame::GetThisObject(uint16_t num_ins) const {
+  mirror::AbstractMethod* m = GetMethod();
+  if (m->IsStatic()) {
+    return NULL;
+  } else {
+    return GetVRegReference(NumberOfVRegs() - num_ins);
+  }
+}
+
 ThrowLocation ShadowFrame::GetCurrentLocationForThrow() const {
   return ThrowLocation(GetThisObject(), GetMethod(), GetDexPC());
 }
diff --git a/src/stack.h b/src/stack.h
index 1b4d285..fbfacb1 100644
--- a/src/stack.h
+++ b/src/stack.h
@@ -202,6 +202,8 @@
 
   mirror::Object* GetThisObject() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  mirror::Object* GetThisObject(uint16_t num_ins) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   ThrowLocation GetCurrentLocationForThrow() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void SetMethod(mirror::AbstractMethod* method) {
@@ -254,13 +256,9 @@
       CHECK_LT(num_vregs, static_cast<uint32_t>(kHasReferenceArray));
       number_of_vregs_ |= kHasReferenceArray;
 #endif
-      for (size_t i = 0; i < num_vregs; ++i) {
-        SetVRegReference(i, NULL);
-      }
+      memset(vregs_, 0, num_vregs * (sizeof(uint32_t) + sizeof(mirror::Object*)));
     } else {
-      for (size_t i = 0; i < num_vregs; ++i) {
-        SetVReg(i, 0);
-      }
+      memset(vregs_, 0, num_vregs * sizeof(uint32_t));
     }
   }
 
diff --git a/src/thread.cc b/src/thread.cc
index c5bfb20..3ed388b 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -53,6 +53,7 @@
 #include "runtime_support.h"
 #include "scoped_thread_state_change.h"
 #include "ScopedLocalRef.h"
+#include "ScopedUtfChars.h"
 #include "sirt_ref.h"
 #include "gc/space.h"
 #include "stack.h"
@@ -605,10 +606,22 @@
     Thread* thread;
     {
       ScopedObjectAccess soa(Thread::Current());
-      MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
+      Thread* self = soa.Self();
+      MutexLock mu(self, *Locks::thread_list_lock_);
       thread = Thread::FromManagedThread(soa, peer);
       if (thread == NULL) {
-        LOG(WARNING) << "No such thread for suspend: " << peer;
+        JNIEnv* env = self->GetJniEnv();
+        ScopedLocalRef<jstring> scoped_name_string(env,
+                                                   (jstring)env->GetObjectField(peer,
+                                                              WellKnownClasses::java_lang_Thread_name));
+        ScopedUtfChars scoped_name_chars(env,scoped_name_string.get());
+        if (scoped_name_chars.c_str() == NULL) {
+            LOG(WARNING) << "No such thread for suspend: " << peer;
+            env->ExceptionClear();
+        } else {
+            LOG(WARNING) << "No such thread for suspend: " << peer << ":" << scoped_name_chars.c_str();
+        }
+
         return NULL;
       }
       {
@@ -865,9 +878,10 @@
   // TODO: we call this code when dying but may not have suspended the thread ourself. The
   //       IsSuspended check is therefore racy with the use for dumping (normally we inhibit
   //       the race with the thread_suspend_count_lock_).
-  if (this == Thread::Current() || IsSuspended()) {
+  bool dump_for_abort = (gAborting > 0);
+  if (this == Thread::Current() || IsSuspended() || dump_for_abort) {
     // If we're currently in native code, dump that stack before dumping the managed stack.
-    if (ShouldShowNativeStack(this)) {
+    if (dump_for_abort || ShouldShowNativeStack(this)) {
       DumpKernelStack(os, GetTid(), "  kernel: ", false);
       DumpNativeStack(os, GetTid(), "  native: ", false);
     }
@@ -1643,10 +1657,14 @@
   ENTRY_POINT_INFO(pShlLong),
   ENTRY_POINT_INFO(pShrLong),
   ENTRY_POINT_INFO(pUshrLong),
+  ENTRY_POINT_INFO(pInterpreterToInterpreterEntry),
+  ENTRY_POINT_INFO(pInterpreterToQuickEntry),
   ENTRY_POINT_INFO(pIndexOf),
   ENTRY_POINT_INFO(pMemcmp16),
   ENTRY_POINT_INFO(pStringCompareTo),
   ENTRY_POINT_INFO(pMemcpy),
+  ENTRY_POINT_INFO(pPortableResolutionTrampolineFromCode),
+  ENTRY_POINT_INFO(pQuickResolutionTrampolineFromCode),
   ENTRY_POINT_INFO(pInvokeDirectTrampolineWithAccessCheck),
   ENTRY_POINT_INFO(pInvokeInterfaceTrampoline),
   ENTRY_POINT_INFO(pInvokeInterfaceTrampolineWithAccessCheck),
diff --git a/src/thread_list.cc b/src/thread_list.cc
index ebb63dd..eacd848 100644
--- a/src/thread_list.cc
+++ b/src/thread_list.cc
@@ -466,10 +466,8 @@
     all_threads_are_daemons = true;
     MutexLock mu(self, *Locks::thread_list_lock_);
     for (It it = list_.begin(), end = list_.end(); it != end; ++it) {
-      // TODO: there's a race here with thread exit that's being worked around by checking if the
-      // thread has a peer.
       Thread* thread = *it;
-      if (thread != self && thread->HasPeer() && !thread->IsDaemon()) {
+      if (thread != self && !thread->IsDaemon()) {
         all_threads_are_daemons = false;
         break;
       }
diff --git a/src/utf.cc b/src/utf.cc
index 8d3547e..1add7d9 100644
--- a/src/utf.cc
+++ b/src/utf.cc
@@ -119,6 +119,23 @@
   }
 }
 
+int CompareModifiedUtf8ToUtf16AsCodePointValues(const char* utf8_1, const uint16_t* utf8_2) {
+  for (;;) {
+    if (*utf8_1 == '\0') {
+      return (*utf8_2 == '\0') ? 0 : -1;
+    } else if (*utf8_2 == '\0') {
+      return 1;
+    }
+
+    int c1 = GetUtf16FromUtf8(&utf8_1);
+    int c2 = *utf8_2;
+
+    if (c1 != c2) {
+      return c1 > c2 ? 1 : -1;
+    }
+  }
+}
+
 size_t CountUtf8Bytes(const uint16_t* chars, size_t char_count) {
   size_t result = 0;
   while (char_count--) {
diff --git a/src/utf.h b/src/utf.h
index 44899bf..57c811f 100644
--- a/src/utf.h
+++ b/src/utf.h
@@ -56,6 +56,12 @@
 int CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(const char* utf8_1, const char* utf8_2);
 
 /*
+ * Compare a modified UTF-8 string with a UTF-16 string as code point values in a non-locale
+ * sensitive manner.
+ */
+int CompareModifiedUtf8ToUtf16AsCodePointValues(const char* utf8_1, const uint16_t* utf8_2);
+
+/*
  * Convert from UTF-16 to Modified UTF-8. Note that the output is _not_
  * NUL-terminated. You probably need to call CountUtf8Bytes before calling
  * this anyway, so if you want a NUL-terminated string, you know where to
diff --git a/src/vector_output_stream.cc b/src/vector_output_stream.cc
index 96154ee..e5ff729 100644
--- a/src/vector_output_stream.cc
+++ b/src/vector_output_stream.cc
@@ -16,8 +16,6 @@
 
 #include "vector_output_stream.h"
 
-#include <string.h>
-
 #include "base/logging.h"
 
 namespace art {
@@ -25,14 +23,6 @@
 VectorOutputStream::VectorOutputStream(const std::string& location, std::vector<uint8_t>& vector)
   : OutputStream(location), offset_(vector.size()), vector_(vector) {}
 
-bool VectorOutputStream::WriteFully(const void* buffer, int64_t byte_count) {
-  off_t new_offset = offset_ + byte_count;
-  EnsureCapacity(new_offset);
-  memcpy(&vector_[offset_], buffer, byte_count);
-  offset_ = new_offset;
-  return true;
-}
-
 off_t VectorOutputStream::Seek(off_t offset, Whence whence) {
   CHECK(whence == kSeekSet || whence == kSeekCurrent || whence == kSeekEnd) << whence;
   off_t new_offset = 0;
@@ -55,10 +45,4 @@
   return offset_;
 }
 
-void VectorOutputStream::EnsureCapacity(off_t new_offset) {
-  if (new_offset > static_cast<off_t>(vector_.size())) {
-    vector_.resize(new_offset);
-  }
-}
-
 }  // namespace art
diff --git a/src/vector_output_stream.h b/src/vector_output_stream.h
index a99128e..3546c8d 100644
--- a/src/vector_output_stream.h
+++ b/src/vector_output_stream.h
@@ -20,6 +20,7 @@
 #include "output_stream.h"
 
 #include <string>
+#include <string.h>
 #include <vector>
 
 namespace art {
@@ -30,12 +31,28 @@
 
   virtual ~VectorOutputStream() {}
 
-  virtual bool WriteFully(const void* buffer, int64_t byte_count);
+  bool WriteFully(const void* buffer, int64_t byte_count) {
+    if (static_cast<size_t>(offset_) == vector_.size()) {
+      const uint8_t* start = reinterpret_cast<const uint8_t*>(buffer);
+      vector_.insert(vector_.end(), &start[0], &start[byte_count]);
+      offset_ += byte_count;
+    } else {
+      off_t new_offset = offset_ + byte_count;
+      EnsureCapacity(new_offset);
+      memcpy(&vector_[offset_], buffer, byte_count);
+      offset_ = new_offset;
+    }
+    return true;
+  }
 
-  virtual off_t Seek(off_t offset, Whence whence);
+  off_t Seek(off_t offset, Whence whence);
 
  private:
-  void EnsureCapacity(off_t new_offset);
+  void EnsureCapacity(off_t new_offset) {
+    if (new_offset > static_cast<off_t>(vector_.size())) {
+      vector_.resize(new_offset);
+    }
+  }
 
   off_t offset_;
   std::vector<uint8_t>& vector_;
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index 2eb0c20..efdd6f6 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -19,11 +19,12 @@
 #include <iostream>
 
 #include "base/logging.h"
+#include "base/mutex-inl.h"
 #include "base/stringpiece.h"
 #include "class_linker.h"
 #include "compiler/driver/compiler_driver.h"
 #include "dex_file-inl.h"
-#include "dex_instruction.h"
+#include "dex_instruction-inl.h"
 #include "dex_instruction_visitor.h"
 #include "gc/card_table-inl.h"
 #include "indenter.h"
@@ -32,11 +33,12 @@
 #include "mirror/abstract_method-inl.h"
 #include "mirror/class.h"
 #include "mirror/class-inl.h"
-#include "mirror/dex_cache.h"
+#include "mirror/dex_cache-inl.h"
 #include "mirror/field-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "object_utils.h"
+#include "register_line-inl.h"
 #include "runtime.h"
 #include "verifier/dex_gc_map.h"
 
@@ -266,13 +268,14 @@
     : reg_types_(can_load_classes),
       work_insn_idx_(-1),
       dex_method_idx_(dex_method_idx),
-      foo_method_(method),
+      mirror_method_(method),
       method_access_flags_(method_access_flags),
       dex_file_(dex_file),
       dex_cache_(dex_cache),
       class_loader_(class_loader),
       class_def_idx_(class_def_idx),
       code_item_(code_item),
+      declaring_class_(NULL),
       interesting_dex_pc_(-1),
       monitor_enter_dex_pcs_(NULL),
       have_pending_hard_failure_(false),
@@ -895,6 +898,7 @@
 
 static const std::vector<uint8_t>* CreateLengthPrefixedDexGcMap(const std::vector<uint8_t>& gc_map) {
   std::vector<uint8_t>* length_prefixed_gc_map = new std::vector<uint8_t>;
+  length_prefixed_gc_map->reserve(gc_map.size() + 4);
   length_prefixed_gc_map->push_back((gc_map.size() & 0xff000000) >> 24);
   length_prefixed_gc_map->push_back((gc_map.size() & 0x00ff0000) >> 16);
   length_prefixed_gc_map->push_back((gc_map.size() & 0x0000ff00) >> 8);
@@ -949,15 +953,20 @@
     DCHECK_NE(failures_.size(), 0U);
     return false;  // Not a real failure, but a failure to encode
   }
-#ifndef NDEBUG
-  VerifyGcMap(*map);
-#endif
+  if (kIsDebugBuild) {
+    VerifyGcMap(*map);
+  }
   const std::vector<uint8_t>* dex_gc_map = CreateLengthPrefixedDexGcMap(*(map.get()));
   verifier::MethodVerifier::SetDexGcMap(ref, *dex_gc_map);
 
-  MethodVerifier::PcToConreteMethod* pc_to_conrete_method = GenerateDevirtMap();
-  if(pc_to_conrete_method != NULL ) {
-    SetDevirtMap(ref, pc_to_conrete_method);
+  MethodVerifier::MethodSafeCastSet* method_to_safe_casts = GenerateSafeCastSet();
+  if(method_to_safe_casts != NULL ) {
+    SetSafeCastMap(ref, method_to_safe_casts);
+  }
+
+  MethodVerifier::PcToConcreteMethodMap* pc_to_concrete_method = GenerateDevirtMap();
+  if(pc_to_concrete_method != NULL ) {
+    SetDevirtMap(ref, pc_to_concrete_method);
   }
   return true;
 }
@@ -1244,6 +1253,11 @@
     if (dead_start >= 0) {
       LogVerifyInfo() << "dead code " << reinterpret_cast<void*>(dead_start) << "-" << reinterpret_cast<void*>(insn_idx - 1);
     }
+    // To dump the state of the verify after a method, do something like:
+    // if (PrettyMethod(dex_method_idx_, *dex_file_) ==
+    //     "boolean java.lang.String.equals(java.lang.Object)") {
+    //   LOG(INFO) << info_messages_.str();
+    // }
   }
   return true;
 }
@@ -1280,7 +1294,6 @@
    */
   const uint16_t* insns = code_item_->insns_ + work_insn_idx_;
   const Instruction* inst = Instruction::At(insns);
-  DecodedInstruction dec_insn(inst);
   int opcode_flags = Instruction::FlagsOf(inst->Opcode());
 
   int32_t branch_target = 0;
@@ -1306,32 +1319,51 @@
 #endif
   }
 
-  switch (dec_insn.opcode) {
+
+  // We need to ensure the work line is consistent while performing validation. When we spot a
+  // peephole pattern we compute a new line for either the fallthrough instruction or the
+  // branch target.
+  UniquePtr<RegisterLine> branch_line;
+  UniquePtr<RegisterLine> fallthrough_line;
+
+  switch (inst->Opcode()) {
     case Instruction::NOP:
       /*
        * A "pure" NOP has no effect on anything. Data tables start with
        * a signature that looks like a NOP; if we see one of these in
        * the course of executing code then we have a problem.
        */
-      if (dec_insn.vA != 0) {
+      if (inst->VRegA_10x() != 0) {
         Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "encountered data table in instruction stream";
       }
       break;
 
     case Instruction::MOVE:
+      work_line_->CopyRegister1(inst->VRegA_12x(), inst->VRegB_12x(), kTypeCategory1nr);
+      break;
     case Instruction::MOVE_FROM16:
+      work_line_->CopyRegister1(inst->VRegA_22x(), inst->VRegB_22x(), kTypeCategory1nr);
+      break;
     case Instruction::MOVE_16:
-      work_line_->CopyRegister1(dec_insn.vA, dec_insn.vB, kTypeCategory1nr);
+      work_line_->CopyRegister1(inst->VRegA_32x(), inst->VRegB_32x(), kTypeCategory1nr);
       break;
     case Instruction::MOVE_WIDE:
+      work_line_->CopyRegister2(inst->VRegA_12x(), inst->VRegB_12x());
+      break;
     case Instruction::MOVE_WIDE_FROM16:
+      work_line_->CopyRegister2(inst->VRegA_22x(), inst->VRegB_22x());
+      break;
     case Instruction::MOVE_WIDE_16:
-      work_line_->CopyRegister2(dec_insn.vA, dec_insn.vB);
+      work_line_->CopyRegister2(inst->VRegA_32x(), inst->VRegB_32x());
       break;
     case Instruction::MOVE_OBJECT:
+      work_line_->CopyRegister1(inst->VRegA_12x(), inst->VRegB_12x(), kTypeCategoryRef);
+      break;
     case Instruction::MOVE_OBJECT_FROM16:
+      work_line_->CopyRegister1(inst->VRegA_22x(), inst->VRegB_22x(), kTypeCategoryRef);
+      break;
     case Instruction::MOVE_OBJECT_16:
-      work_line_->CopyRegister1(dec_insn.vA, dec_insn.vB, kTypeCategoryRef);
+      work_line_->CopyRegister1(inst->VRegA_32x(), inst->VRegB_32x(), kTypeCategoryRef);
       break;
 
     /*
@@ -1346,13 +1378,13 @@
      * easier to read in some cases.)
      */
     case Instruction::MOVE_RESULT:
-      work_line_->CopyResultRegister1(dec_insn.vA, false);
+      work_line_->CopyResultRegister1(inst->VRegA_11x(), false);
       break;
     case Instruction::MOVE_RESULT_WIDE:
-      work_line_->CopyResultRegister2(dec_insn.vA);
+      work_line_->CopyResultRegister2(inst->VRegA_11x());
       break;
     case Instruction::MOVE_RESULT_OBJECT:
-      work_line_->CopyResultRegister1(dec_insn.vA, true);
+      work_line_->CopyResultRegister1(inst->VRegA_11x(), true);
       break;
 
     case Instruction::MOVE_EXCEPTION: {
@@ -1361,7 +1393,7 @@
        * that as part of extracting the exception type from the catch block list.
        */
       const RegType& res_type = GetCaughtExceptionType();
-      work_line_->SetRegisterType(dec_insn.vA, res_type);
+      work_line_->SetRegisterType(inst->VRegA_11x(), res_type);
       break;
     }
     case Instruction::RETURN_VOID:
@@ -1380,16 +1412,17 @@
         } else {
           // Compilers may generate synthetic functions that write byte values into boolean fields.
           // Also, it may use integer values for boolean, byte, short, and character return types.
-          const RegType& src_type = work_line_->GetRegisterType(dec_insn.vA);
+          const uint32_t vregA = inst->VRegA_11x();
+          const RegType& src_type = work_line_->GetRegisterType(vregA);
           bool use_src = ((return_type.IsBoolean() && src_type.IsByte()) ||
                           ((return_type.IsBoolean() || return_type.IsByte() ||
                            return_type.IsShort() || return_type.IsChar()) &&
                            src_type.IsInteger()));
           /* check the register contents */
           bool success =
-              work_line_->VerifyRegisterType(dec_insn.vA, use_src ? src_type : return_type);
+              work_line_->VerifyRegisterType(vregA, use_src ? src_type : return_type);
           if (!success) {
-            AppendToLastFailMessage(StringPrintf(" return-1nr on invalid register v%d", dec_insn.vA));
+            AppendToLastFailMessage(StringPrintf(" return-1nr on invalid register v%d", vregA));
           }
         }
       }
@@ -1402,9 +1435,10 @@
           Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "return-wide not expected";
         } else {
           /* check the register contents */
-          bool success = work_line_->VerifyRegisterType(dec_insn.vA, return_type);
+          const uint32_t vregA = inst->VRegA_11x();
+          bool success = work_line_->VerifyRegisterType(vregA, return_type);
           if (!success) {
-            AppendToLastFailMessage(StringPrintf(" return-wide on invalid register v%d", dec_insn.vA));
+            AppendToLastFailMessage(StringPrintf(" return-wide on invalid register v%d", vregA));
           }
         }
       }
@@ -1418,7 +1452,8 @@
           /* return_type is the *expected* return type, not register value */
           DCHECK(!return_type.IsZero());
           DCHECK(!return_type.IsUninitializedReference());
-          const RegType& reg_type = work_line_->GetRegisterType(dec_insn.vA);
+          const uint32_t vregA = inst->VRegA_11x();
+          const RegType& reg_type = work_line_->GetRegisterType(vregA);
           // Disallow returning uninitialized values and verify that the reference in vAA is an
           // instance of the "return_type"
           if (reg_type.IsUninitializedTypes()) {
@@ -1432,66 +1467,71 @@
       break;
 
       /* could be boolean, int, float, or a null reference */
-    case Instruction::CONST_4:
-      work_line_->SetRegisterType(dec_insn.vA,
-                                  reg_types_.FromCat1Const(static_cast<int32_t>(dec_insn.vB << 28) >> 28, true));
+    case Instruction::CONST_4: {
+      int32_t val = static_cast<int32_t>(inst->VRegB_11n() << 28) >> 28;
+      work_line_->SetRegisterType(inst->VRegA_11n(), reg_types_.FromCat1Const(val, true));
       break;
-    case Instruction::CONST_16:
-      work_line_->SetRegisterType(dec_insn.vA,
-                                  reg_types_.FromCat1Const(static_cast<int16_t>(dec_insn.vB), true));
+    }
+    case Instruction::CONST_16: {
+      int16_t val = static_cast<int16_t>(inst->VRegB_21s());
+      work_line_->SetRegisterType(inst->VRegA_21s(), reg_types_.FromCat1Const(val, true));
       break;
+    }
     case Instruction::CONST:
-      work_line_->SetRegisterType(dec_insn.vA, reg_types_.FromCat1Const(dec_insn.vB, true));
+      work_line_->SetRegisterType(inst->VRegA_31i(),
+                                  reg_types_.FromCat1Const(inst->VRegB_31i(), true));
       break;
     case Instruction::CONST_HIGH16:
-      work_line_->SetRegisterType(dec_insn.vA,
-                                  reg_types_.FromCat1Const(dec_insn.vB << 16, true));
+      work_line_->SetRegisterType(inst->VRegA_21h(),
+                                  reg_types_.FromCat1Const(inst->VRegB_21h() << 16, true));
       break;
       /* could be long or double; resolved upon use */
     case Instruction::CONST_WIDE_16: {
-      int64_t val = static_cast<int16_t>(dec_insn.vB);
+      int64_t val = static_cast<int16_t>(inst->VRegB_21s());
       const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
       const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
-      work_line_->SetRegisterTypeWide(dec_insn.vA, lo, hi);
+      work_line_->SetRegisterTypeWide(inst->VRegA_21s(), lo, hi);
       break;
     }
     case Instruction::CONST_WIDE_32: {
-      int64_t val = static_cast<int32_t>(dec_insn.vB);
+      int64_t val = static_cast<int32_t>(inst->VRegB_31i());
       const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
       const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
-      work_line_->SetRegisterTypeWide(dec_insn.vA, lo, hi);
+      work_line_->SetRegisterTypeWide(inst->VRegA_31i(), lo, hi);
       break;
     }
     case Instruction::CONST_WIDE: {
-      int64_t val = dec_insn.vB_wide;
+      int64_t val = inst->VRegB_51l();
       const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
       const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
-      work_line_->SetRegisterTypeWide(dec_insn.vA, lo, hi);
+      work_line_->SetRegisterTypeWide(inst->VRegA_51l(), lo, hi);
       break;
     }
     case Instruction::CONST_WIDE_HIGH16: {
-      int64_t val = static_cast<uint64_t>(dec_insn.vB) << 48;
+      int64_t val = static_cast<uint64_t>(inst->VRegB_21h()) << 48;
       const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
       const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
-      work_line_->SetRegisterTypeWide(dec_insn.vA, lo, hi);
+      work_line_->SetRegisterTypeWide(inst->VRegA_21h(), lo, hi);
       break;
     }
     case Instruction::CONST_STRING:
+      work_line_->SetRegisterType(inst->VRegA_21c(), reg_types_.JavaLangString());
+      break;
     case Instruction::CONST_STRING_JUMBO:
-      work_line_->SetRegisterType(dec_insn.vA, reg_types_.JavaLangString());
+      work_line_->SetRegisterType(inst->VRegA_31c(), reg_types_.JavaLangString());
       break;
     case Instruction::CONST_CLASS: {
       // Get type from instruction if unresolved then we need an access check
       // TODO: check Compiler::CanAccessTypeWithoutChecks returns false when res_type is unresolved
-      const RegType& res_type = ResolveClassAndCheckAccess(dec_insn.vB);
+      const RegType& res_type = ResolveClassAndCheckAccess(inst->VRegB_21c());
       // Register holds class, ie its type is class, on error it will hold Conflict.
-      work_line_->SetRegisterType(dec_insn.vA,
+      work_line_->SetRegisterType(inst->VRegA_21c(),
                                   res_type.IsConflict() ? res_type
                                                         : reg_types_.JavaLangClass(true));
       break;
     }
     case Instruction::MONITOR_ENTER:
-      work_line_->PushMonitor(dec_insn.vA, work_insn_idx_);
+      work_line_->PushMonitor(inst->VRegA_11x(), work_insn_idx_);
       break;
     case Instruction::MONITOR_EXIT:
       /*
@@ -1515,7 +1555,7 @@
        * "live" so we still need to check it.
        */
       opcode_flags &= ~Instruction::kThrow;
-      work_line_->PopMonitor(dec_insn.vA);
+      work_line_->PopMonitor(inst->VRegA_11x());
       break;
 
     case Instruction::CHECK_CAST:
@@ -1527,45 +1567,53 @@
        * If it fails, an exception is thrown, which we deal with later by ignoring the update to
        * dec_insn.vA when branching to a handler.
        */
-      bool is_checkcast = dec_insn.opcode == Instruction::CHECK_CAST;
-      const RegType& res_type =
-          ResolveClassAndCheckAccess(is_checkcast ? dec_insn.vB : dec_insn.vC);
+      const bool is_checkcast = (inst->Opcode() == Instruction::CHECK_CAST);
+      const uint32_t type_idx = (is_checkcast) ? inst->VRegB_21c() : inst->VRegC_22c();
+      const RegType& res_type = ResolveClassAndCheckAccess(type_idx);
       if (res_type.IsConflict()) {
         DCHECK_NE(failures_.size(), 0U);
         if (!is_checkcast) {
-          work_line_->SetRegisterType(dec_insn.vA, reg_types_.Boolean());
+          work_line_->SetRegisterType(inst->VRegA_22c(), reg_types_.Boolean());
         }
         break;  // bad class
       }
       // TODO: check Compiler::CanAccessTypeWithoutChecks returns false when res_type is unresolved
-      const RegType& orig_type =
-          work_line_->GetRegisterType(is_checkcast ? dec_insn.vA : dec_insn.vB);
+      uint32_t orig_type_reg = (is_checkcast) ? inst->VRegA_21c() : inst->VRegB_22c();
+      const RegType& orig_type = work_line_->GetRegisterType(orig_type_reg);
       if (!res_type.IsNonZeroReferenceTypes()) {
-        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "check-cast on unexpected class " << res_type;
+        if (is_checkcast) {
+          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "check-cast on unexpected class " << res_type;
+        } else {
+          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "instance-of on unexpected class " << res_type;
+        }
       } else if (!orig_type.IsReferenceTypes()) {
-        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "check-cast on non-reference in v" << dec_insn.vA;
+        if (is_checkcast) {
+          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "check-cast on non-reference in v" << orig_type_reg;
+        } else {
+          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "instance-of on non-reference in v" << orig_type_reg;
+        }
       } else {
         if (is_checkcast) {
-          work_line_->SetRegisterType(dec_insn.vA, res_type);
+          work_line_->SetRegisterType(inst->VRegA_21c(), res_type);
         } else {
-          work_line_->SetRegisterType(dec_insn.vA, reg_types_.Boolean());
+          work_line_->SetRegisterType(inst->VRegA_22c(), reg_types_.Boolean());
         }
       }
       break;
     }
     case Instruction::ARRAY_LENGTH: {
-      const RegType& res_type = work_line_->GetRegisterType(dec_insn.vB);
+      const RegType& res_type = work_line_->GetRegisterType(inst->VRegB_12x());
       if (res_type.IsReferenceTypes()) {
         if (!res_type.IsArrayTypes() && !res_type.IsZero()) {  // ie not an array or null
           Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "array-length on non-array " << res_type;
         } else {
-          work_line_->SetRegisterType(dec_insn.vA, reg_types_.Integer());
+          work_line_->SetRegisterType(inst->VRegA_12x(), reg_types_.Integer());
         }
       }
       break;
     }
     case Instruction::NEW_INSTANCE: {
-      const RegType& res_type = ResolveClassAndCheckAccess(dec_insn.vB);
+      const RegType& res_type = ResolveClassAndCheckAccess(inst->VRegB_21c());
       if (res_type.IsConflict()) {
         DCHECK_NE(failures_.size(), 0U);
         break;  // bad class
@@ -1582,55 +1630,55 @@
       // initialized must be marked invalid.
       work_line_->MarkUninitRefsAsInvalid(uninit_type);
       // add the new uninitialized reference to the register state
-      work_line_->SetRegisterType(dec_insn.vA, uninit_type);
+      work_line_->SetRegisterType(inst->VRegA_21c(), uninit_type);
       break;
     }
     case Instruction::NEW_ARRAY:
-      VerifyNewArray(dec_insn, false, false);
+      VerifyNewArray(inst, false, false);
       break;
     case Instruction::FILLED_NEW_ARRAY:
-      VerifyNewArray(dec_insn, true, false);
+      VerifyNewArray(inst, true, false);
       just_set_result = true;  // Filled new array sets result register
       break;
     case Instruction::FILLED_NEW_ARRAY_RANGE:
-      VerifyNewArray(dec_insn, true, true);
+      VerifyNewArray(inst, true, true);
       just_set_result = true;  // Filled new array range sets result register
       break;
     case Instruction::CMPL_FLOAT:
     case Instruction::CMPG_FLOAT:
-      if (!work_line_->VerifyRegisterType(dec_insn.vB, reg_types_.Float())) {
+      if (!work_line_->VerifyRegisterType(inst->VRegB_23x(), reg_types_.Float())) {
         break;
       }
-      if (!work_line_->VerifyRegisterType(dec_insn.vC, reg_types_.Float())) {
+      if (!work_line_->VerifyRegisterType(inst->VRegC_23x(), reg_types_.Float())) {
         break;
       }
-      work_line_->SetRegisterType(dec_insn.vA, reg_types_.Integer());
+      work_line_->SetRegisterType(inst->VRegA_23x(), reg_types_.Integer());
       break;
     case Instruction::CMPL_DOUBLE:
     case Instruction::CMPG_DOUBLE:
-      if (!work_line_->VerifyRegisterTypeWide(dec_insn.vB, reg_types_.DoubleLo(),
+      if (!work_line_->VerifyRegisterTypeWide(inst->VRegB_23x(), reg_types_.DoubleLo(),
                                               reg_types_.DoubleHi())) {
         break;
       }
-      if (!work_line_->VerifyRegisterTypeWide(dec_insn.vC, reg_types_.DoubleLo(),
+      if (!work_line_->VerifyRegisterTypeWide(inst->VRegC_23x(), reg_types_.DoubleLo(),
                                               reg_types_.DoubleHi())) {
         break;
       }
-      work_line_->SetRegisterType(dec_insn.vA, reg_types_.Integer());
+      work_line_->SetRegisterType(inst->VRegA_23x(), reg_types_.Integer());
       break;
     case Instruction::CMP_LONG:
-      if (!work_line_->VerifyRegisterTypeWide(dec_insn.vB, reg_types_.LongLo(),
+      if (!work_line_->VerifyRegisterTypeWide(inst->VRegB_23x(), reg_types_.LongLo(),
                                               reg_types_.LongHi())) {
         break;
       }
-      if (!work_line_->VerifyRegisterTypeWide(dec_insn.vC, reg_types_.LongLo(),
+      if (!work_line_->VerifyRegisterTypeWide(inst->VRegC_23x(), reg_types_.LongLo(),
                                               reg_types_.LongHi())) {
         break;
       }
-      work_line_->SetRegisterType(dec_insn.vA, reg_types_.Integer());
+      work_line_->SetRegisterType(inst->VRegA_23x(), reg_types_.Integer());
       break;
     case Instruction::THROW: {
-      const RegType& res_type = work_line_->GetRegisterType(dec_insn.vA);
+      const RegType& res_type = work_line_->GetRegisterType(inst->VRegA_11x());
       if (!reg_types_.JavaLangThrowable(false).IsAssignableFrom(res_type)) {
         Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "thrown class " << res_type << " not instanceof Throwable";
       }
@@ -1645,12 +1693,12 @@
     case Instruction::PACKED_SWITCH:
     case Instruction::SPARSE_SWITCH:
       /* verify that vAA is an integer, or can be converted to one */
-      work_line_->VerifyRegisterType(dec_insn.vA, reg_types_.Integer());
+      work_line_->VerifyRegisterType(inst->VRegA_31t(), reg_types_.Integer());
       break;
 
     case Instruction::FILL_ARRAY_DATA: {
       /* Similar to the verification done for APUT */
-      const RegType& array_type = work_line_->GetRegisterType(dec_insn.vA);
+      const RegType& array_type = work_line_->GetRegisterType(inst->VRegA_31t());
       /* array_type can be null if the reg type is Zero */
       if (!array_type.IsZero()) {
         if (!array_type.IsArrayTypes()) {
@@ -1683,8 +1731,8 @@
     }
     case Instruction::IF_EQ:
     case Instruction::IF_NE: {
-      const RegType& reg_type1 = work_line_->GetRegisterType(dec_insn.vA);
-      const RegType& reg_type2 = work_line_->GetRegisterType(dec_insn.vB);
+      const RegType& reg_type1 = work_line_->GetRegisterType(inst->VRegA_22t());
+      const RegType& reg_type2 = work_line_->GetRegisterType(inst->VRegB_22t());
       bool mismatch = false;
       if (reg_type1.IsZero()) {  // zero then integral or reference expected
         mismatch = !reg_type2.IsReferenceTypes() && !reg_type2.IsIntegralTypes();
@@ -1703,8 +1751,8 @@
     case Instruction::IF_GE:
     case Instruction::IF_GT:
     case Instruction::IF_LE: {
-      const RegType& reg_type1 = work_line_->GetRegisterType(dec_insn.vA);
-      const RegType& reg_type2 = work_line_->GetRegisterType(dec_insn.vB);
+      const RegType& reg_type1 = work_line_->GetRegisterType(inst->VRegA_22t());
+      const RegType& reg_type2 = work_line_->GetRegisterType(inst->VRegB_22t());
       if (!reg_type1.IsIntegralTypes() || !reg_type2.IsIntegralTypes()) {
         Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "args to 'if' (" << reg_type1 << ","
                                           << reg_type2 << ") must be integral";
@@ -1713,17 +1761,94 @@
     }
     case Instruction::IF_EQZ:
     case Instruction::IF_NEZ: {
-      const RegType& reg_type = work_line_->GetRegisterType(dec_insn.vA);
+      const RegType& reg_type = work_line_->GetRegisterType(inst->VRegA_21t());
       if (!reg_type.IsReferenceTypes() && !reg_type.IsIntegralTypes()) {
         Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "type " << reg_type << " unexpected as arg to if-eqz/if-nez";
       }
+
+      // Find previous instruction - its existence is a precondition to peephole optimization.
+      uint32_t instance_of_idx = 0;
+      if (0 != work_insn_idx_) {
+        instance_of_idx = work_insn_idx_ - 1;
+        while(0 != instance_of_idx && !insn_flags_[instance_of_idx].IsOpcode()) {
+          instance_of_idx--;
+        }
+        CHECK(insn_flags_[instance_of_idx].IsOpcode());
+      } else {
+        break;
+      }
+
+      const Instruction* instance_of_inst = Instruction::At(code_item_->insns_ + instance_of_idx);
+
+      /* Check for peep-hole pattern of:
+       *    ...;
+       *    instance-of vX, vY, T;
+       *    ifXXX vX, label ;
+       *    ...;
+       * label:
+       *    ...;
+       * and sharpen the type of vY to be type T.
+       * Note, this pattern can't be if:
+       *  - if there are other branches to this branch,
+       *  - when vX == vY.
+       */
+      if (!CurrentInsnFlags()->IsBranchTarget() &&
+          (Instruction::INSTANCE_OF == instance_of_inst->Opcode()) &&
+          (inst->VRegA_21t() == instance_of_inst->VRegA_22c()) &&
+          (instance_of_inst->VRegA_22c() != instance_of_inst->VRegB_22c())) {
+        // Check that the we are not attempting conversion to interface types,
+        // which is not done because of the multiple inheritance implications.
+        const RegType& cast_type = ResolveClassAndCheckAccess(instance_of_inst->VRegC_22c());
+
+        if(!cast_type.IsUnresolvedTypes() && !cast_type.GetClass()->IsInterface()) {
+          RegisterLine* update_line = new RegisterLine(code_item_->registers_size_, this);
+          if (inst->Opcode() == Instruction::IF_EQZ) {
+            fallthrough_line.reset(update_line);
+          } else {
+            branch_line.reset(update_line);
+          }
+          update_line->CopyFromLine(work_line_.get());
+          update_line->SetRegisterType(instance_of_inst->VRegB_22c(), cast_type);
+          if (!insn_flags_[instance_of_idx].IsBranchTarget() && 0 != instance_of_idx) {
+            // See if instance-of was preceded by a move-object operation, common due to the small
+            // register encoding space of instance-of, and propagate type information to the source
+            // of the move-object.
+            uint32_t move_idx = instance_of_idx - 1;
+            while(0 != move_idx && !insn_flags_[move_idx].IsOpcode()) {
+              move_idx--;
+            }
+            CHECK(insn_flags_[move_idx].IsOpcode());
+            const Instruction* move_inst = Instruction::At(code_item_->insns_ + move_idx);
+            switch (move_inst->Opcode()) {
+              case Instruction::MOVE_OBJECT:
+                if (move_inst->VRegA_12x() == instance_of_inst->VRegB_22c()) {
+                  update_line->SetRegisterType(move_inst->VRegB_12x(), cast_type);
+                }
+                break;
+              case Instruction::MOVE_OBJECT_FROM16:
+                if (move_inst->VRegA_22x() == instance_of_inst->VRegB_22c()) {
+                  update_line->SetRegisterType(move_inst->VRegB_22x(), cast_type);
+                }
+                break;
+              case Instruction::MOVE_OBJECT_16:
+                if (move_inst->VRegA_32x() == instance_of_inst->VRegB_22c()) {
+                  update_line->SetRegisterType(move_inst->VRegB_32x(), cast_type);
+                }
+                break;
+              default:
+                break;
+            }
+          }
+        }
+      }
+
       break;
     }
     case Instruction::IF_LTZ:
     case Instruction::IF_GEZ:
     case Instruction::IF_GTZ:
     case Instruction::IF_LEZ: {
-      const RegType& reg_type = work_line_->GetRegisterType(dec_insn.vA);
+      const RegType& reg_type = work_line_->GetRegisterType(inst->VRegA_21t());
       if (!reg_type.IsIntegralTypes()) {
         Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "type " << reg_type
                                           << " unexpected as arg to if-ltz/if-gez/if-gtz/if-lez";
@@ -1731,150 +1856,150 @@
       break;
     }
     case Instruction::AGET_BOOLEAN:
-      VerifyAGet(dec_insn, reg_types_.Boolean(), true);
+      VerifyAGet(inst, reg_types_.Boolean(), true);
       break;
     case Instruction::AGET_BYTE:
-      VerifyAGet(dec_insn, reg_types_.Byte(), true);
+      VerifyAGet(inst, reg_types_.Byte(), true);
       break;
     case Instruction::AGET_CHAR:
-      VerifyAGet(dec_insn, reg_types_.Char(), true);
+      VerifyAGet(inst, reg_types_.Char(), true);
       break;
     case Instruction::AGET_SHORT:
-      VerifyAGet(dec_insn, reg_types_.Short(), true);
+      VerifyAGet(inst, reg_types_.Short(), true);
       break;
     case Instruction::AGET:
-      VerifyAGet(dec_insn, reg_types_.Integer(), true);
+      VerifyAGet(inst, reg_types_.Integer(), true);
       break;
     case Instruction::AGET_WIDE:
-      VerifyAGet(dec_insn, reg_types_.LongLo(), true);
+      VerifyAGet(inst, reg_types_.LongLo(), true);
       break;
     case Instruction::AGET_OBJECT:
-      VerifyAGet(dec_insn, reg_types_.JavaLangObject(false), false);
+      VerifyAGet(inst, reg_types_.JavaLangObject(false), false);
       break;
 
     case Instruction::APUT_BOOLEAN:
-      VerifyAPut(dec_insn, reg_types_.Boolean(), true);
+      VerifyAPut(inst, reg_types_.Boolean(), true);
       break;
     case Instruction::APUT_BYTE:
-      VerifyAPut(dec_insn, reg_types_.Byte(), true);
+      VerifyAPut(inst, reg_types_.Byte(), true);
       break;
     case Instruction::APUT_CHAR:
-      VerifyAPut(dec_insn, reg_types_.Char(), true);
+      VerifyAPut(inst, reg_types_.Char(), true);
       break;
     case Instruction::APUT_SHORT:
-      VerifyAPut(dec_insn, reg_types_.Short(), true);
+      VerifyAPut(inst, reg_types_.Short(), true);
       break;
     case Instruction::APUT:
-      VerifyAPut(dec_insn, reg_types_.Integer(), true);
+      VerifyAPut(inst, reg_types_.Integer(), true);
       break;
     case Instruction::APUT_WIDE:
-      VerifyAPut(dec_insn, reg_types_.LongLo(), true);
+      VerifyAPut(inst, reg_types_.LongLo(), true);
       break;
     case Instruction::APUT_OBJECT:
-      VerifyAPut(dec_insn, reg_types_.JavaLangObject(false), false);
+      VerifyAPut(inst, reg_types_.JavaLangObject(false), false);
       break;
 
     case Instruction::IGET_BOOLEAN:
-      VerifyISGet(dec_insn, reg_types_.Boolean(), true, false);
+      VerifyISGet(inst, reg_types_.Boolean(), true, false);
       break;
     case Instruction::IGET_BYTE:
-      VerifyISGet(dec_insn, reg_types_.Byte(), true, false);
+      VerifyISGet(inst, reg_types_.Byte(), true, false);
       break;
     case Instruction::IGET_CHAR:
-      VerifyISGet(dec_insn, reg_types_.Char(), true, false);
+      VerifyISGet(inst, reg_types_.Char(), true, false);
       break;
     case Instruction::IGET_SHORT:
-      VerifyISGet(dec_insn, reg_types_.Short(), true, false);
+      VerifyISGet(inst, reg_types_.Short(), true, false);
       break;
     case Instruction::IGET:
-      VerifyISGet(dec_insn, reg_types_.Integer(), true, false);
+      VerifyISGet(inst, reg_types_.Integer(), true, false);
       break;
     case Instruction::IGET_WIDE:
-      VerifyISGet(dec_insn, reg_types_.LongLo(), true, false);
+      VerifyISGet(inst, reg_types_.LongLo(), true, false);
       break;
     case Instruction::IGET_OBJECT:
-      VerifyISGet(dec_insn, reg_types_.JavaLangObject(false), false, false);
+      VerifyISGet(inst, reg_types_.JavaLangObject(false), false, false);
       break;
 
     case Instruction::IPUT_BOOLEAN:
-      VerifyISPut(dec_insn, reg_types_.Boolean(), true, false);
+      VerifyISPut(inst, reg_types_.Boolean(), true, false);
       break;
     case Instruction::IPUT_BYTE:
-      VerifyISPut(dec_insn, reg_types_.Byte(), true, false);
+      VerifyISPut(inst, reg_types_.Byte(), true, false);
       break;
     case Instruction::IPUT_CHAR:
-      VerifyISPut(dec_insn, reg_types_.Char(), true, false);
+      VerifyISPut(inst, reg_types_.Char(), true, false);
       break;
     case Instruction::IPUT_SHORT:
-      VerifyISPut(dec_insn, reg_types_.Short(), true, false);
+      VerifyISPut(inst, reg_types_.Short(), true, false);
       break;
     case Instruction::IPUT:
-      VerifyISPut(dec_insn, reg_types_.Integer(), true, false);
+      VerifyISPut(inst, reg_types_.Integer(), true, false);
       break;
     case Instruction::IPUT_WIDE:
-      VerifyISPut(dec_insn, reg_types_.LongLo(), true, false);
+      VerifyISPut(inst, reg_types_.LongLo(), true, false);
       break;
     case Instruction::IPUT_OBJECT:
-      VerifyISPut(dec_insn, reg_types_.JavaLangObject(false), false, false);
+      VerifyISPut(inst, reg_types_.JavaLangObject(false), false, false);
       break;
 
     case Instruction::SGET_BOOLEAN:
-      VerifyISGet(dec_insn, reg_types_.Boolean(), true, true);
+      VerifyISGet(inst, reg_types_.Boolean(), true, true);
       break;
     case Instruction::SGET_BYTE:
-      VerifyISGet(dec_insn, reg_types_.Byte(), true, true);
+      VerifyISGet(inst, reg_types_.Byte(), true, true);
       break;
     case Instruction::SGET_CHAR:
-      VerifyISGet(dec_insn, reg_types_.Char(), true, true);
+      VerifyISGet(inst, reg_types_.Char(), true, true);
       break;
     case Instruction::SGET_SHORT:
-      VerifyISGet(dec_insn, reg_types_.Short(), true, true);
+      VerifyISGet(inst, reg_types_.Short(), true, true);
       break;
     case Instruction::SGET:
-      VerifyISGet(dec_insn, reg_types_.Integer(), true, true);
+      VerifyISGet(inst, reg_types_.Integer(), true, true);
       break;
     case Instruction::SGET_WIDE:
-      VerifyISGet(dec_insn, reg_types_.LongLo(), true, true);
+      VerifyISGet(inst, reg_types_.LongLo(), true, true);
       break;
     case Instruction::SGET_OBJECT:
-      VerifyISGet(dec_insn, reg_types_.JavaLangObject(false), false, true);
+      VerifyISGet(inst, reg_types_.JavaLangObject(false), false, true);
       break;
 
     case Instruction::SPUT_BOOLEAN:
-      VerifyISPut(dec_insn, reg_types_.Boolean(), true, true);
+      VerifyISPut(inst, reg_types_.Boolean(), true, true);
       break;
     case Instruction::SPUT_BYTE:
-      VerifyISPut(dec_insn, reg_types_.Byte(), true, true);
+      VerifyISPut(inst, reg_types_.Byte(), true, true);
       break;
     case Instruction::SPUT_CHAR:
-      VerifyISPut(dec_insn, reg_types_.Char(), true, true);
+      VerifyISPut(inst, reg_types_.Char(), true, true);
       break;
     case Instruction::SPUT_SHORT:
-      VerifyISPut(dec_insn, reg_types_.Short(), true, true);
+      VerifyISPut(inst, reg_types_.Short(), true, true);
       break;
     case Instruction::SPUT:
-      VerifyISPut(dec_insn, reg_types_.Integer(), true, true);
+      VerifyISPut(inst, reg_types_.Integer(), true, true);
       break;
     case Instruction::SPUT_WIDE:
-      VerifyISPut(dec_insn, reg_types_.LongLo(), true, true);
+      VerifyISPut(inst, reg_types_.LongLo(), true, true);
       break;
     case Instruction::SPUT_OBJECT:
-      VerifyISPut(dec_insn, reg_types_.JavaLangObject(false), false, true);
+      VerifyISPut(inst, reg_types_.JavaLangObject(false), false, true);
       break;
 
     case Instruction::INVOKE_VIRTUAL:
     case Instruction::INVOKE_VIRTUAL_RANGE:
     case Instruction::INVOKE_SUPER:
     case Instruction::INVOKE_SUPER_RANGE: {
-      bool is_range = (dec_insn.opcode == Instruction::INVOKE_VIRTUAL_RANGE ||
-                       dec_insn.opcode == Instruction::INVOKE_SUPER_RANGE);
-      bool is_super =  (dec_insn.opcode == Instruction::INVOKE_SUPER ||
-                        dec_insn.opcode == Instruction::INVOKE_SUPER_RANGE);
-      mirror::AbstractMethod* called_method = VerifyInvocationArgs(dec_insn, METHOD_VIRTUAL,
+      bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE ||
+                       inst->Opcode() == Instruction::INVOKE_SUPER_RANGE);
+      bool is_super =  (inst->Opcode() == Instruction::INVOKE_SUPER ||
+                        inst->Opcode() == Instruction::INVOKE_SUPER_RANGE);
+      mirror::AbstractMethod* called_method = VerifyInvocationArgs(inst, METHOD_VIRTUAL,
                                                                    is_range, is_super);
       const char* descriptor;
       if (called_method == NULL) {
-        uint32_t method_idx = dec_insn.vB;
+        uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
         const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
         uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
         descriptor =  dex_file_->StringByTypeIdx(return_type_idx);
@@ -1892,13 +2017,13 @@
     }
     case Instruction::INVOKE_DIRECT:
     case Instruction::INVOKE_DIRECT_RANGE: {
-      bool is_range = (dec_insn.opcode == Instruction::INVOKE_DIRECT_RANGE);
-      mirror::AbstractMethod* called_method = VerifyInvocationArgs(dec_insn, METHOD_DIRECT,
+      bool is_range = (inst->Opcode() == Instruction::INVOKE_DIRECT_RANGE);
+      mirror::AbstractMethod* called_method = VerifyInvocationArgs(inst, METHOD_DIRECT,
                                                                    is_range, false);
       const char* return_type_descriptor;
       bool is_constructor;
       if (called_method == NULL) {
-        uint32_t method_idx = dec_insn.vB;
+        uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
         const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
         is_constructor = StringPiece(dex_file_->GetMethodName(method_id)) == "<init>";
         uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
@@ -1915,7 +2040,7 @@
          * allowing the latter only if the "this" argument is the same as the "this" argument to
          * this method (which implies that we're in a constructor ourselves).
          */
-        const RegType& this_type = work_line_->GetInvocationThis(dec_insn);
+        const RegType& this_type = work_line_->GetInvocationThis(inst, is_range);
         if (this_type.IsConflict())  // failure.
           break;
 
@@ -1959,11 +2084,11 @@
     }
     case Instruction::INVOKE_STATIC:
     case Instruction::INVOKE_STATIC_RANGE: {
-        bool is_range = (dec_insn.opcode == Instruction::INVOKE_STATIC_RANGE);
-        mirror::AbstractMethod* called_method = VerifyInvocationArgs(dec_insn, METHOD_STATIC, is_range, false);
+        bool is_range = (inst->Opcode() == Instruction::INVOKE_STATIC_RANGE);
+        mirror::AbstractMethod* called_method = VerifyInvocationArgs(inst, METHOD_STATIC, is_range, false);
         const char* descriptor;
         if (called_method == NULL) {
-          uint32_t method_idx = dec_insn.vB;
+          uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
           const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
           uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
           descriptor =  dex_file_->StringByTypeIdx(return_type_idx);
@@ -1981,8 +2106,8 @@
       break;
     case Instruction::INVOKE_INTERFACE:
     case Instruction::INVOKE_INTERFACE_RANGE: {
-      bool is_range =  (dec_insn.opcode == Instruction::INVOKE_INTERFACE_RANGE);
-      mirror::AbstractMethod* abs_method = VerifyInvocationArgs(dec_insn, METHOD_INTERFACE, is_range, false);
+      bool is_range =  (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE);
+      mirror::AbstractMethod* abs_method = VerifyInvocationArgs(inst, METHOD_INTERFACE, is_range, false);
       if (abs_method != NULL) {
         mirror::Class* called_interface = abs_method->GetDeclaringClass();
         if (!called_interface->IsInterface() && !called_interface->IsObjectClass()) {
@@ -1994,7 +2119,7 @@
       /* Get the type of the "this" arg, which should either be a sub-interface of called
        * interface or Object (see comments in RegType::JoinClass).
        */
-      const RegType& this_type = work_line_->GetInvocationThis(dec_insn);
+      const RegType& this_type = work_line_->GetInvocationThis(inst, is_range);
       if (this_type.IsZero()) {
         /* null pointer always passes (and always fails at runtime) */
       } else {
@@ -2017,7 +2142,7 @@
        */
       const char* descriptor;
       if (abs_method == NULL) {
-        uint32_t method_idx = dec_insn.vB;
+        uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
         const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
         uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
         descriptor =  dex_file_->StringByTypeIdx(return_type_idx);
@@ -2035,74 +2160,74 @@
     }
     case Instruction::NEG_INT:
     case Instruction::NOT_INT:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Integer(), reg_types_.Integer());
+      work_line_->CheckUnaryOp(inst, reg_types_.Integer(), reg_types_.Integer());
       break;
     case Instruction::NEG_LONG:
     case Instruction::NOT_LONG:
-      work_line_->CheckUnaryOpWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+      work_line_->CheckUnaryOpWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
                                    reg_types_.LongLo(), reg_types_.LongHi());
       break;
     case Instruction::NEG_FLOAT:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Float(), reg_types_.Float());
+      work_line_->CheckUnaryOp(inst, reg_types_.Float(), reg_types_.Float());
       break;
     case Instruction::NEG_DOUBLE:
-      work_line_->CheckUnaryOpWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+      work_line_->CheckUnaryOpWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
                                    reg_types_.DoubleLo(), reg_types_.DoubleHi());
       break;
     case Instruction::INT_TO_LONG:
-      work_line_->CheckUnaryOpToWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+      work_line_->CheckUnaryOpToWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
                                      reg_types_.Integer());
       break;
     case Instruction::INT_TO_FLOAT:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Float(), reg_types_.Integer());
+      work_line_->CheckUnaryOp(inst, reg_types_.Float(), reg_types_.Integer());
       break;
     case Instruction::INT_TO_DOUBLE:
-      work_line_->CheckUnaryOpToWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+      work_line_->CheckUnaryOpToWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
                                      reg_types_.Integer());
       break;
     case Instruction::LONG_TO_INT:
-      work_line_->CheckUnaryOpFromWide(dec_insn, reg_types_.Integer(),
+      work_line_->CheckUnaryOpFromWide(inst, reg_types_.Integer(),
                                        reg_types_.LongLo(), reg_types_.LongHi());
       break;
     case Instruction::LONG_TO_FLOAT:
-      work_line_->CheckUnaryOpFromWide(dec_insn, reg_types_.Float(),
+      work_line_->CheckUnaryOpFromWide(inst, reg_types_.Float(),
                                        reg_types_.LongLo(), reg_types_.LongHi());
       break;
     case Instruction::LONG_TO_DOUBLE:
-      work_line_->CheckUnaryOpWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+      work_line_->CheckUnaryOpWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
                                    reg_types_.LongLo(), reg_types_.LongHi());
       break;
     case Instruction::FLOAT_TO_INT:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Integer(), reg_types_.Float());
+      work_line_->CheckUnaryOp(inst, reg_types_.Integer(), reg_types_.Float());
       break;
     case Instruction::FLOAT_TO_LONG:
-      work_line_->CheckUnaryOpToWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+      work_line_->CheckUnaryOpToWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
                                      reg_types_.Float());
       break;
     case Instruction::FLOAT_TO_DOUBLE:
-      work_line_->CheckUnaryOpToWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+      work_line_->CheckUnaryOpToWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
                                      reg_types_.Float());
       break;
     case Instruction::DOUBLE_TO_INT:
-      work_line_->CheckUnaryOpFromWide(dec_insn, reg_types_.Integer(),
+      work_line_->CheckUnaryOpFromWide(inst, reg_types_.Integer(),
                                        reg_types_.DoubleLo(), reg_types_.DoubleHi());
       break;
     case Instruction::DOUBLE_TO_LONG:
-      work_line_->CheckUnaryOpWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+      work_line_->CheckUnaryOpWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
                                    reg_types_.DoubleLo(), reg_types_.DoubleHi());
       break;
     case Instruction::DOUBLE_TO_FLOAT:
-      work_line_->CheckUnaryOpFromWide(dec_insn, reg_types_.Float(),
+      work_line_->CheckUnaryOpFromWide(inst, reg_types_.Float(),
                                        reg_types_.DoubleLo(), reg_types_.DoubleHi());
       break;
     case Instruction::INT_TO_BYTE:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Byte(), reg_types_.Integer());
+      work_line_->CheckUnaryOp(inst, reg_types_.Byte(), reg_types_.Integer());
       break;
     case Instruction::INT_TO_CHAR:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Char(), reg_types_.Integer());
+      work_line_->CheckUnaryOp(inst, reg_types_.Char(), reg_types_.Integer());
       break;
     case Instruction::INT_TO_SHORT:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Short(), reg_types_.Integer());
+      work_line_->CheckUnaryOp(inst, reg_types_.Short(), reg_types_.Integer());
       break;
 
     case Instruction::ADD_INT:
@@ -2113,13 +2238,13 @@
     case Instruction::SHL_INT:
     case Instruction::SHR_INT:
     case Instruction::USHR_INT:
-      work_line_->CheckBinaryOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(),
+      work_line_->CheckBinaryOp(inst, reg_types_.Integer(), reg_types_.Integer(),
                                 reg_types_.Integer(), false);
       break;
     case Instruction::AND_INT:
     case Instruction::OR_INT:
     case Instruction::XOR_INT:
-      work_line_->CheckBinaryOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(),
+      work_line_->CheckBinaryOp(inst, reg_types_.Integer(), reg_types_.Integer(),
                                 reg_types_.Integer(), true);
       break;
     case Instruction::ADD_LONG:
@@ -2130,7 +2255,7 @@
     case Instruction::AND_LONG:
     case Instruction::OR_LONG:
     case Instruction::XOR_LONG:
-      work_line_->CheckBinaryOpWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+      work_line_->CheckBinaryOpWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
                                     reg_types_.LongLo(), reg_types_.LongHi(),
                                     reg_types_.LongLo(), reg_types_.LongHi());
       break;
@@ -2138,7 +2263,7 @@
     case Instruction::SHR_LONG:
     case Instruction::USHR_LONG:
       /* shift distance is Int, making these different from other binary operations */
-      work_line_->CheckBinaryOpWideShift(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+      work_line_->CheckBinaryOpWideShift(inst, reg_types_.LongLo(), reg_types_.LongHi(),
                                          reg_types_.Integer());
       break;
     case Instruction::ADD_FLOAT:
@@ -2146,14 +2271,14 @@
     case Instruction::MUL_FLOAT:
     case Instruction::DIV_FLOAT:
     case Instruction::REM_FLOAT:
-      work_line_->CheckBinaryOp(dec_insn, reg_types_.Float(), reg_types_.Float(), reg_types_.Float(), false);
+      work_line_->CheckBinaryOp(inst, reg_types_.Float(), reg_types_.Float(), reg_types_.Float(), false);
       break;
     case Instruction::ADD_DOUBLE:
     case Instruction::SUB_DOUBLE:
     case Instruction::MUL_DOUBLE:
     case Instruction::DIV_DOUBLE:
     case Instruction::REM_DOUBLE:
-      work_line_->CheckBinaryOpWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+      work_line_->CheckBinaryOpWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
                                     reg_types_.DoubleLo(), reg_types_.DoubleHi(),
                                     reg_types_.DoubleLo(), reg_types_.DoubleHi());
       break;
@@ -2164,15 +2289,15 @@
     case Instruction::SHL_INT_2ADDR:
     case Instruction::SHR_INT_2ADDR:
     case Instruction::USHR_INT_2ADDR:
-      work_line_->CheckBinaryOp2addr(dec_insn, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false);
+      work_line_->CheckBinaryOp2addr(inst, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false);
       break;
     case Instruction::AND_INT_2ADDR:
     case Instruction::OR_INT_2ADDR:
     case Instruction::XOR_INT_2ADDR:
-      work_line_->CheckBinaryOp2addr(dec_insn, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), true);
+      work_line_->CheckBinaryOp2addr(inst, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), true);
       break;
     case Instruction::DIV_INT_2ADDR:
-      work_line_->CheckBinaryOp2addr(dec_insn, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false);
+      work_line_->CheckBinaryOp2addr(inst, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false);
       break;
     case Instruction::ADD_LONG_2ADDR:
     case Instruction::SUB_LONG_2ADDR:
@@ -2182,14 +2307,14 @@
     case Instruction::AND_LONG_2ADDR:
     case Instruction::OR_LONG_2ADDR:
     case Instruction::XOR_LONG_2ADDR:
-      work_line_->CheckBinaryOp2addrWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+      work_line_->CheckBinaryOp2addrWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
                                          reg_types_.LongLo(), reg_types_.LongHi(),
                                          reg_types_.LongLo(), reg_types_.LongHi());
       break;
     case Instruction::SHL_LONG_2ADDR:
     case Instruction::SHR_LONG_2ADDR:
     case Instruction::USHR_LONG_2ADDR:
-      work_line_->CheckBinaryOp2addrWideShift(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+      work_line_->CheckBinaryOp2addrWideShift(inst, reg_types_.LongLo(), reg_types_.LongHi(),
                                               reg_types_.Integer());
       break;
     case Instruction::ADD_FLOAT_2ADDR:
@@ -2197,14 +2322,14 @@
     case Instruction::MUL_FLOAT_2ADDR:
     case Instruction::DIV_FLOAT_2ADDR:
     case Instruction::REM_FLOAT_2ADDR:
-      work_line_->CheckBinaryOp2addr(dec_insn, reg_types_.Float(), reg_types_.Float(), reg_types_.Float(), false);
+      work_line_->CheckBinaryOp2addr(inst, reg_types_.Float(), reg_types_.Float(), reg_types_.Float(), false);
       break;
     case Instruction::ADD_DOUBLE_2ADDR:
     case Instruction::SUB_DOUBLE_2ADDR:
     case Instruction::MUL_DOUBLE_2ADDR:
     case Instruction::DIV_DOUBLE_2ADDR:
     case Instruction::REM_DOUBLE_2ADDR:
-      work_line_->CheckBinaryOp2addrWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+      work_line_->CheckBinaryOp2addrWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
                                          reg_types_.DoubleLo(),  reg_types_.DoubleHi(),
                                          reg_types_.DoubleLo(), reg_types_.DoubleHi());
       break;
@@ -2213,12 +2338,12 @@
     case Instruction::MUL_INT_LIT16:
     case Instruction::DIV_INT_LIT16:
     case Instruction::REM_INT_LIT16:
-      work_line_->CheckLiteralOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(), false);
+      work_line_->CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), false, true);
       break;
     case Instruction::AND_INT_LIT16:
     case Instruction::OR_INT_LIT16:
     case Instruction::XOR_INT_LIT16:
-      work_line_->CheckLiteralOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(), true);
+      work_line_->CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), true, true);
       break;
     case Instruction::ADD_INT_LIT8:
     case Instruction::RSUB_INT_LIT8:
@@ -2228,12 +2353,12 @@
     case Instruction::SHL_INT_LIT8:
     case Instruction::SHR_INT_LIT8:
     case Instruction::USHR_INT_LIT8:
-      work_line_->CheckLiteralOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(), false);
+      work_line_->CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), false, false);
       break;
     case Instruction::AND_INT_LIT8:
     case Instruction::OR_INT_LIT8:
     case Instruction::XOR_INT_LIT8:
-      work_line_->CheckLiteralOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(), true);
+      work_line_->CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), true, false);
       break;
 
     /* These should never appear during verification. */
@@ -2305,33 +2430,7 @@
     work_line_->SetResultTypeToUnknown();
   }
 
-  /* Handle "continue". Tag the next consecutive instruction. */
-  if ((opcode_flags & Instruction::kContinue) != 0) {
-    uint32_t next_insn_idx = work_insn_idx_ + CurrentInsnFlags()->GetLengthInCodeUnits();
-    if (next_insn_idx >= code_item_->insns_size_in_code_units_) {
-      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Execution can walk off end of code area";
-      return false;
-    }
-    // The only way to get to a move-exception instruction is to get thrown there. Make sure the
-    // next instruction isn't one.
-    if (!CheckNotMoveException(code_item_->insns_, next_insn_idx)) {
-      return false;
-    }
-    RegisterLine* next_line = reg_table_.GetLine(next_insn_idx);
-    if (next_line != NULL) {
-      // Merge registers into what we have for the next instruction, and set the "changed" flag if
-      // needed.
-      if (!UpdateRegisters(next_insn_idx, work_line_.get())) {
-        return false;
-      }
-    } else {
-      /*
-       * We're not recording register data for the next instruction, so we don't know what the prior
-       * state was. We have to assume that something has changed and re-evaluate it.
-       */
-      insn_flags_[next_insn_idx].SetChanged();
-    }
-  }
+
 
   /*
    * Handle "branch". Tag the branch target.
@@ -2357,8 +2456,14 @@
       return false;
     }
     /* update branch target, set "changed" if appropriate */
-    if (!UpdateRegisters(work_insn_idx_ + branch_target, work_line_.get())) {
-      return false;
+    if (NULL != branch_line.get()) {
+      if (!UpdateRegisters(work_insn_idx_ + branch_target, branch_line.get())) {
+        return false;
+      }
+    } else {
+      if (!UpdateRegisters(work_insn_idx_ + branch_target, work_line_.get())) {
+        return false;
+      }
     }
   }
 
@@ -2433,7 +2538,7 @@
        * monitor-enter and the monitor stack was empty, we don't need a catch-all (if it throws,
        * it will do so before grabbing the lock).
        */
-      if (dec_insn.opcode != Instruction::MONITOR_ENTER || work_line_->MonitorStackDepth() != 1) {
+      if (inst->Opcode() != Instruction::MONITOR_ENTER || work_line_->MonitorStackDepth() != 1) {
         Fail(VERIFY_ERROR_BAD_CLASS_HARD)
             << "expected to be within a catch-all for an instruction where a monitor is held";
         return false;
@@ -2441,6 +2546,42 @@
     }
   }
 
+  /* Handle "continue". Tag the next consecutive instruction.
+   *  Note: Keep the code handling "continue" case below the "branch" and "switch" cases,
+   *        because it changes work_line_ when performing peephole optimization
+   *        and this change should not be used in those cases.
+   */
+    if ((opcode_flags & Instruction::kContinue) != 0) {
+      uint32_t next_insn_idx = work_insn_idx_ + CurrentInsnFlags()->GetLengthInCodeUnits();
+      if (next_insn_idx >= code_item_->insns_size_in_code_units_) {
+        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Execution can walk off end of code area";
+        return false;
+      }
+      // The only way to get to a move-exception instruction is to get thrown there. Make sure the
+      // next instruction isn't one.
+      if (!CheckNotMoveException(code_item_->insns_, next_insn_idx)) {
+        return false;
+      }
+      if (NULL != fallthrough_line.get()) {
+        // Make workline consistent with fallthrough computed from peephole optimization.
+        work_line_->CopyFromLine(fallthrough_line.get());
+      }
+      RegisterLine* next_line = reg_table_.GetLine(next_insn_idx);
+      if (next_line != NULL) {
+        // Merge registers into what we have for the next instruction,
+        // and set the "changed" flag if needed.
+        if (!UpdateRegisters(next_insn_idx, work_line_.get())) {
+          return false;
+        }
+      } else {
+        /*
+         * We're not recording register data for the next instruction, so we don't know what the
+         * prior state was. We have to assume that something has changed and re-evaluate it.
+         */
+        insn_flags_[next_insn_idx].SetChanged();
+      }
+    }
+
   /* If we're returning from the method, make sure monitor stack is empty. */
   if ((opcode_flags & Instruction::kReturn) != 0) {
     if (!work_line_->VerifyMonitorStackEmpty()) {
@@ -2472,7 +2613,8 @@
   const RegType& referrer = GetDeclaringClass();
   mirror::Class* klass = dex_cache_->GetResolvedType(class_idx);
   const RegType& result =
-      klass != NULL ? reg_types_.FromClass(klass, klass->IsFinal())
+      klass != NULL ? reg_types_.FromClass(descriptor, klass,
+                                           klass->CannotBeAssignedFromOtherTypes())
                     : reg_types_.FromDescriptor(class_loader_, descriptor, false);
   if (result.IsConflict()) {
     Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "accessing broken descriptor '" << descriptor
@@ -2625,12 +2767,14 @@
   return res_method;
 }
 
-mirror::AbstractMethod* MethodVerifier::VerifyInvocationArgs(const DecodedInstruction& dec_insn,
-                                                             MethodType method_type, bool is_range,
+mirror::AbstractMethod* MethodVerifier::VerifyInvocationArgs(const Instruction* inst,
+                                                             MethodType method_type,
+                                                             bool is_range,
                                                              bool is_super) {
   // Resolve the method. This could be an abstract or concrete method depending on what sort of call
   // we're making.
-  mirror::AbstractMethod* res_method = ResolveMethodAndCheckAccess(dec_insn.vB, method_type);
+  const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
+  mirror::AbstractMethod* res_method = ResolveMethodAndCheckAccess(method_idx, method_type);
   if (res_method == NULL) {  // error or class is unresolved
     return NULL;
   }
@@ -2660,7 +2804,7 @@
   // We use vAA as our expected arg count, rather than res_method->insSize, because we need to
   // match the call to the signature. Also, we might might be calling through an abstract method
   // definition (which doesn't have register count values).
-  size_t expected_args = dec_insn.vA;
+  const size_t expected_args = (is_range) ? inst->VRegA_3rc() : inst->VRegA_35c();
   /* caught by static verifier */
   DCHECK(is_range || expected_args <= 5);
   if (expected_args > code_item_->outs_size_) {
@@ -2676,7 +2820,7 @@
    */
   size_t actual_args = 0;
   if (!res_method->IsStatic()) {
-    const RegType& actual_arg_type = work_line_->GetInvocationThis(dec_insn);
+    const RegType& actual_arg_type = work_line_->GetInvocationThis(inst, is_range);
     if (actual_arg_type.IsConflict()) {  // GetInvocationThis failed.
       return NULL;
     }
@@ -2686,7 +2830,9 @@
     }
     if (method_type != METHOD_INTERFACE && !actual_arg_type.IsZero()) {
       mirror::Class* klass = res_method->GetDeclaringClass();
-      const RegType& res_method_class = reg_types_.FromClass(klass, klass->IsFinal());
+      const RegType& res_method_class =
+          reg_types_.FromClass(ClassHelper(klass).GetDescriptor(), klass,
+                               klass->CannotBeAssignedFromOtherTypes());
       if (!res_method_class.IsAssignableFrom(actual_arg_type)) {
         Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "'this' argument '" << actual_arg_type
             << "' not instance of '" << res_method_class << "'";
@@ -2702,6 +2848,10 @@
   MethodHelper mh(res_method);
   const DexFile::TypeList* params = mh.GetParameterTypeList();
   size_t params_size = params == NULL ? 0 : params->Size();
+  uint32_t arg[5];
+  if (!is_range) {
+    inst->GetArgs(arg);
+  }
   for (size_t param_index = 0; param_index < params_size; param_index++) {
     if (actual_args >= expected_args) {
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invalid call to '" << PrettyMethod(res_method)
@@ -2717,7 +2867,7 @@
       return NULL;
     }
     const RegType& reg_type = reg_types_.FromDescriptor(class_loader_, descriptor, false);
-    uint32_t get_reg = is_range ? dec_insn.vC + actual_args : dec_insn.arg[actual_args];
+    uint32_t get_reg = is_range ? inst->VRegC_3rc() + actual_args : arg[actual_args];
     if (!work_line_->VerifyRegisterType(get_reg, reg_type)) {
       return res_method;
     }
@@ -2732,9 +2882,19 @@
   }
 }
 
-void MethodVerifier::VerifyNewArray(const DecodedInstruction& dec_insn, bool is_filled,
-                                 bool is_range) {
-  const RegType& res_type = ResolveClassAndCheckAccess(is_filled ? dec_insn.vB : dec_insn.vC);
+void MethodVerifier::VerifyNewArray(const Instruction* inst, bool is_filled, bool is_range) {
+  uint32_t type_idx;
+  if (!is_filled) {
+    DCHECK_EQ(inst->Opcode(), Instruction::NEW_ARRAY);
+    type_idx = inst->VRegC_22c();
+  } else if (!is_range) {
+    DCHECK_EQ(inst->Opcode(), Instruction::FILLED_NEW_ARRAY);
+    type_idx = inst->VRegB_35c();
+  } else {
+    DCHECK_EQ(inst->Opcode(), Instruction::FILLED_NEW_ARRAY_RANGE);
+    type_idx = inst->VRegB_3rc();
+  }
+  const RegType& res_type = ResolveClassAndCheckAccess(type_idx);
   if (res_type.IsConflict()) {  // bad class
     DCHECK_NE(failures_.size(), 0U);
   } else {
@@ -2743,43 +2903,49 @@
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "new-array on non-array class " << res_type;
     } else if (!is_filled) {
       /* make sure "size" register is valid type */
-      work_line_->VerifyRegisterType(dec_insn.vB, reg_types_.Integer());
+      work_line_->VerifyRegisterType(inst->VRegB_22c(), reg_types_.Integer());
       /* set register type to array class */
-      work_line_->SetRegisterType(dec_insn.vA, res_type);
+      const RegType& precise_type = reg_types_.FromUninitialized(res_type);
+      work_line_->SetRegisterType(inst->VRegA_22c(), precise_type);
     } else {
       // Verify each register. If "arg_count" is bad, VerifyRegisterType() will run off the end of
       // the list and fail. It's legal, if silly, for arg_count to be zero.
       const RegType& expected_type = reg_types_.GetComponentType(res_type, class_loader_);
-      uint32_t arg_count = dec_insn.vA;
+      uint32_t arg_count = (is_range) ? inst->VRegA_3rc() : inst->VRegA_35c();
+      uint32_t arg[5];
+      if (!is_range) {
+        inst->GetArgs(arg);
+      }
       for (size_t ui = 0; ui < arg_count; ui++) {
-        uint32_t get_reg = is_range ? dec_insn.vC + ui : dec_insn.arg[ui];
+        uint32_t get_reg = is_range ? inst->VRegC_3rc() + ui : arg[ui];
         if (!work_line_->VerifyRegisterType(get_reg, expected_type)) {
           work_line_->SetResultRegisterType(reg_types_.Conflict());
           return;
         }
       }
       // filled-array result goes into "result" register
-      work_line_->SetResultRegisterType(res_type);
+      const RegType& precise_type = reg_types_.FromUninitialized(res_type);
+      work_line_->SetResultRegisterType(precise_type);
     }
   }
 }
 
-void MethodVerifier::VerifyAGet(const DecodedInstruction& dec_insn,
+void MethodVerifier::VerifyAGet(const Instruction* inst,
                                 const RegType& insn_type, bool is_primitive) {
-  const RegType& index_type = work_line_->GetRegisterType(dec_insn.vC);
+  const RegType& index_type = work_line_->GetRegisterType(inst->VRegC_23x());
   if (!index_type.IsArrayIndexTypes()) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Invalid reg type for array index (" << index_type << ")";
   } else {
-    const RegType& array_type = work_line_->GetRegisterType(dec_insn.vB);
+    const RegType& array_type = work_line_->GetRegisterType(inst->VRegB_23x());
     if (array_type.IsZero()) {
       // Null array class; this code path will fail at runtime. Infer a merge-able type from the
       // instruction type. TODO: have a proper notion of bottom here.
       if (!is_primitive || insn_type.IsCategory1Types()) {
         // Reference or category 1
-        work_line_->SetRegisterType(dec_insn.vA, reg_types_.Zero());
+        work_line_->SetRegisterType(inst->VRegA_23x(), reg_types_.Zero());
       } else {
         // Category 2
-        work_line_->SetRegisterTypeWide(dec_insn.vA, reg_types_.FromCat2ConstLo(0, false),
+        work_line_->SetRegisterTypeWide(inst->VRegA_23x(), reg_types_.FromCat2ConstLo(0, false),
                                         reg_types_.FromCat2ConstHi(0, false));
       }
     } else if (!array_type.IsArrayTypes()) {
@@ -2803,9 +2969,9 @@
         // instruction, which can't differentiate object types and ints from floats, longs from
         // doubles.
         if (!component_type.IsLowHalf()) {
-          work_line_->SetRegisterType(dec_insn.vA, component_type);
+          work_line_->SetRegisterType(inst->VRegA_23x(), component_type);
         } else {
-          work_line_->SetRegisterTypeWide(dec_insn.vA, component_type,
+          work_line_->SetRegisterTypeWide(inst->VRegA_23x(), component_type,
                                           component_type.HighHalf(&reg_types_));
         }
       }
@@ -2813,13 +2979,13 @@
   }
 }
 
-void MethodVerifier::VerifyAPut(const DecodedInstruction& dec_insn,
+void MethodVerifier::VerifyAPut(const Instruction* inst,
                              const RegType& insn_type, bool is_primitive) {
-  const RegType& index_type = work_line_->GetRegisterType(dec_insn.vC);
+  const RegType& index_type = work_line_->GetRegisterType(inst->VRegC_23x());
   if (!index_type.IsArrayIndexTypes()) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Invalid reg type for array index (" << index_type << ")";
   } else {
-    const RegType& array_type = work_line_->GetRegisterType(dec_insn.vB);
+    const RegType& array_type = work_line_->GetRegisterType(inst->VRegB_23x());
     if (array_type.IsZero()) {
       // Null array type; this code path will fail at runtime. Infer a merge-able type from the
       // instruction type.
@@ -2843,7 +3009,7 @@
         // The instruction agrees with the type of array, confirm the value to be stored does too
         // Note: we use the instruction type (rather than the component type) for aput-object as
         // incompatible classes will be caught at runtime as an array store exception
-        work_line_->VerifyRegisterType(dec_insn.vA, is_primitive ? component_type : insn_type);
+        work_line_->VerifyRegisterType(inst->VRegA_23x(), is_primitive ? component_type : insn_type);
       }
     }
   }
@@ -2865,7 +3031,7 @@
   mirror::Field* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS(*dex_file_, field_idx,
                                                                        dex_cache_, class_loader_);
   if (field == NULL) {
-    LOG(INFO) << "unable to resolve static field " << field_idx << " ("
+    LOG(INFO) << "Unable to resolve static field " << field_idx << " ("
               << dex_file_->GetFieldName(field_id) << ") in "
               << dex_file_->GetFieldDeclaringClassDescriptor(field_id);
     DCHECK(Thread::Current()->IsExceptionPending());
@@ -2900,7 +3066,7 @@
   mirror::Field* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS(*dex_file_, field_idx,
                                                                        dex_cache_, class_loader_);
   if (field == NULL) {
-    LOG(INFO) << "unable to resolve instance field " << field_idx << " ("
+    LOG(INFO) << "Unable to resolve instance field " << field_idx << " ("
               << dex_file_->GetFieldName(field_id) << ") in "
               << dex_file_->GetFieldDeclaringClassDescriptor(field_id);
     DCHECK(Thread::Current()->IsExceptionPending());
@@ -2920,7 +3086,9 @@
     return field;
   } else {
     mirror::Class* klass = field->GetDeclaringClass();
-    const RegType& field_klass = reg_types_.FromClass(klass, klass->IsFinal());
+    const RegType& field_klass =
+        reg_types_.FromClass(dex_file_->GetFieldDeclaringClassDescriptor(field_id),
+                             klass, klass->CannotBeAssignedFromOtherTypes());
     if (obj_type.IsUninitializedTypes() &&
         (!IsConstructor() || GetDeclaringClass().Equals(obj_type) ||
             !field_klass.Equals(GetDeclaringClass()))) {
@@ -2943,14 +3111,14 @@
   }
 }
 
-void MethodVerifier::VerifyISGet(const DecodedInstruction& dec_insn,
-                              const RegType& insn_type, bool is_primitive, bool is_static) {
-  uint32_t field_idx = is_static ? dec_insn.vB : dec_insn.vC;
+void MethodVerifier::VerifyISGet(const Instruction* inst, const RegType& insn_type,
+                                 bool is_primitive, bool is_static) {
+  uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
   mirror::Field* field;
   if (is_static) {
     field = GetStaticField(field_idx);
   } else {
-    const RegType& object_type = work_line_->GetRegisterType(dec_insn.vB);
+    const RegType& object_type = work_line_->GetRegisterType(inst->VRegB_22c());
     field = GetInstanceField(object_type, field_idx);
   }
   const char* descriptor;
@@ -2964,6 +3132,7 @@
     loader = class_loader_;
   }
   const RegType& field_type = reg_types_.FromDescriptor(loader, descriptor, false);
+  const uint32_t vregA = (is_static) ? inst->VRegA_21c() : inst->VRegA_22c();
   if (is_primitive) {
     if (field_type.Equals(insn_type) ||
         (field_type.IsFloat() && insn_type.IsIntegralTypes()) ||
@@ -2985,25 +3154,25 @@
                                         << " to be compatible with type '" << insn_type
                                         << "' but found type '" << field_type
                                         << "' in get-object";
-      work_line_->SetRegisterType(dec_insn.vA, reg_types_.Conflict());
+      work_line_->SetRegisterType(vregA, reg_types_.Conflict());
       return;
     }
   }
   if (!field_type.IsLowHalf()) {
-    work_line_->SetRegisterType(dec_insn.vA, field_type);
+    work_line_->SetRegisterType(vregA, field_type);
   } else {
-    work_line_->SetRegisterTypeWide(dec_insn.vA, field_type, field_type.HighHalf(&reg_types_));
+    work_line_->SetRegisterTypeWide(vregA, field_type, field_type.HighHalf(&reg_types_));
   }
 }
 
-void MethodVerifier::VerifyISPut(const DecodedInstruction& dec_insn,
-                              const RegType& insn_type, bool is_primitive, bool is_static) {
-  uint32_t field_idx = is_static ? dec_insn.vB : dec_insn.vC;
+void MethodVerifier::VerifyISPut(const Instruction* inst, const RegType& insn_type,
+                                 bool is_primitive, bool is_static) {
+  uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
   mirror::Field* field;
   if (is_static) {
     field = GetStaticField(field_idx);
   } else {
-    const RegType& object_type = work_line_->GetRegisterType(dec_insn.vB);
+    const RegType& object_type = work_line_->GetRegisterType(inst->VRegB_22c());
     field = GetInstanceField(object_type, field_idx);
   }
   const char* descriptor;
@@ -3024,11 +3193,12 @@
       return;
     }
   }
+  const uint32_t vregA = (is_static) ? inst->VRegA_21c() : inst->VRegA_22c();
   if (is_primitive) {
     // Primitive field assignability rules are weaker than regular assignability rules
     bool instruction_compatible;
     bool value_compatible;
-    const RegType& value_type = work_line_->GetRegisterType(dec_insn.vA);
+    const RegType& value_type = work_line_->GetRegisterType(vregA);
     if (field_type.IsIntegralTypes()) {
       instruction_compatible = insn_type.IsIntegralTypes();
       value_compatible = value_type.IsIntegralTypes();
@@ -3056,7 +3226,7 @@
       return;
     }
     if (!value_compatible) {
-      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected value in v" << dec_insn.vA
+      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected value in v" << vregA
           << " of type " << value_type
           << " but expected " << field_type
           << " for store to " << PrettyField(field) << " in put";
@@ -3070,7 +3240,7 @@
                                         << "' in put-object";
       return;
     }
-    work_line_->VerifyRegisterType(dec_insn.vA, field_type);
+    work_line_->VerifyRegisterType(vregA, field_type);
   }
 }
 
@@ -3128,14 +3298,18 @@
 }
 
 const RegType& MethodVerifier::GetDeclaringClass() {
-  if (foo_method_ != NULL) {
-    mirror::Class* klass = foo_method_->GetDeclaringClass();
-    return reg_types_.FromClass(klass, klass->IsFinal());
-  } else {
+  if (declaring_class_ == NULL) {
     const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_);
     const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(method_id.class_idx_));
-    return reg_types_.FromDescriptor(class_loader_, descriptor, false);
+    if (mirror_method_ != NULL) {
+      mirror::Class* klass = mirror_method_->GetDeclaringClass();
+      declaring_class_ = &reg_types_.FromClass(descriptor, klass,
+                                               klass->CannotBeAssignedFromOtherTypes());
+    } else {
+      declaring_class_ = &reg_types_.FromDescriptor(class_loader_, descriptor, false);
+    }
   }
+  return *declaring_class_;
 }
 
 void MethodVerifier::ComputeGcMapSizes(size_t* gc_points, size_t* ref_bitmap_bits,
@@ -3160,7 +3334,39 @@
   *log2_max_gc_pc = i;
 }
 
-MethodVerifier::PcToConreteMethod* MethodVerifier::GenerateDevirtMap() {
+MethodVerifier::MethodSafeCastSet* MethodVerifier::GenerateSafeCastSet() {
+  /*
+   * Walks over the method code and adds any cast instructions in which
+   * the type cast is implicit to a set, which is used in the code generation
+   * to elide these casts.
+   */
+  if (!failure_messages_.empty()) {
+    return NULL;
+  }
+  UniquePtr<MethodSafeCastSet> mscs;
+  const Instruction* inst = Instruction::At(code_item_->insns_);
+  const Instruction* end = Instruction::At(code_item_->insns_ +
+                                           code_item_->insns_size_in_code_units_);
+
+  for (; inst < end; inst = inst->Next()) {
+    if (Instruction::CHECK_CAST != inst->Opcode()) {
+      continue;
+    }
+    uint32_t dex_pc = inst->GetDexPc(code_item_->insns_);
+    RegisterLine* line = reg_table_.GetLine(dex_pc);
+    const RegType& reg_type(line->GetRegisterType(inst->VRegA_21c()));
+    const RegType& cast_type = ResolveClassAndCheckAccess(inst->VRegB_21c());
+    if (cast_type.IsStrictlyAssignableFrom(reg_type)) {
+      if (mscs.get() == NULL) {
+        mscs.reset(new MethodSafeCastSet());
+      }
+      mscs->insert(dex_pc);
+    }
+  }
+  return mscs.release();
+}
+
+MethodVerifier::PcToConcreteMethodMap* MethodVerifier::GenerateDevirtMap() {
 
   // It is risky to rely on reg_types for sharpening in cases of soft
   // verification, we might end up sharpening to a wrong implementation. Just abort.
@@ -3168,39 +3374,43 @@
     return NULL;
   }
 
-  PcToConreteMethod* pc_to_concrete_method = new PcToConreteMethod();
-  uint32_t dex_pc = 0;
+  UniquePtr<PcToConcreteMethodMap> pc_to_concrete_method_map;
   const uint16_t* insns = code_item_->insns_ ;
   const Instruction* inst = Instruction::At(insns);
+  const Instruction* end = Instruction::At(insns + code_item_->insns_size_in_code_units_);
 
-  for (; dex_pc < code_item_->insns_size_in_code_units_;
-         dex_pc += insn_flags_[dex_pc].GetLengthInCodeUnits(), inst = inst->Next()) {
-
+  for (; inst < end; inst = inst->Next()) {
     bool is_virtual   = (inst->Opcode() == Instruction::INVOKE_VIRTUAL) ||
         (inst->Opcode() ==  Instruction::INVOKE_VIRTUAL_RANGE);
     bool is_interface = (inst->Opcode() == Instruction::INVOKE_INTERFACE) ||
         (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE);
 
-   if(!(is_interface || is_virtual))
-     continue;
-
-    // Check if vC ("this" pointer in the instruction) has a precise type.
-    RegisterLine* line = reg_table_.GetLine(dex_pc);
-    DecodedInstruction dec_insn(inst);
-    const RegType& reg_type(line->GetRegisterType(dec_insn.vC));
-
-    if (!reg_type.IsPreciseReference()) {
-       continue;
+    if(!is_interface && !is_virtual) {
+      continue;
     }
+    // Get reg type for register holding the reference to the object that will be dispatched upon.
+    uint32_t dex_pc = inst->GetDexPc(insns);
+    RegisterLine* line = reg_table_.GetLine(dex_pc);
+    bool is_range = (inst->Opcode() ==  Instruction::INVOKE_VIRTUAL_RANGE) ||
+        (inst->Opcode() ==  Instruction::INVOKE_INTERFACE_RANGE);
+    const RegType&
+        reg_type(line->GetRegisterType(is_range ? inst->VRegC_3rc() : inst->VRegC_35c()));
 
-    CHECK(!(reg_type.GetClass()->IsInterface()));
-    // If the class is an array class, it can be both Abstract and final and so
-    // the reg_type will be created as precise.
-    CHECK(!(reg_type.GetClass()->IsAbstract()) || reg_type.GetClass()->IsArrayClass());
-    // Find the abstract method.
-    // vB has the method index.
-    mirror::AbstractMethod* abstract_method =  NULL ;
-    abstract_method =  dex_cache_->GetResolvedMethod(dec_insn.vB);
+    if (!reg_type.HasClass()) {
+      // We will compute devirtualization information only when we know the Class of the reg type.
+      continue;
+    }
+    mirror::Class* reg_class = reg_type.GetClass();
+    if (reg_class->IsInterface()) {
+      // We can't devirtualize when the known type of the register is an interface.
+      continue;
+    }
+    if (reg_class->IsAbstract() && !reg_class->IsArrayClass()) {
+      // We can't devirtualize abstract classes except on arrays of abstract classes.
+      continue;
+    }
+    mirror::AbstractMethod* abstract_method =
+        dex_cache_->GetResolvedMethod(is_range ? inst->VRegB_3rc() : inst->VRegB_35c());
     if(abstract_method == NULL) {
       // If the method is not found in the cache this means that it was never found
       // by ResolveMethodAndCheckAccess() called when verifying invoke_*.
@@ -3214,28 +3424,24 @@
     if (is_virtual) {
       concrete_method = reg_type.GetClass()->FindVirtualMethodForVirtual(abstract_method);
     }
-
-    if(concrete_method == NULL) {
-      // In cases where concrete_method is not found continue to the next invoke instead
-      // of crashing.
+    if (concrete_method == NULL || concrete_method->IsAbstract()) {
+      // In cases where concrete_method is not found, or is abstract, continue to the next invoke.
       continue;
     }
-
-    CHECK(!concrete_method->IsAbstract()) << PrettyMethod(concrete_method);
-    // Build method reference.
-    CompilerDriver::MethodReference concrete_ref(
-        concrete_method->GetDeclaringClass()->GetDexCache()->GetDexFile(),
-        concrete_method->GetDexMethodIndex());
-    // Now Save the current PC and the concrete method reference to be used
-    // in compiler driver.
-    pc_to_concrete_method->Put(dex_pc, concrete_ref );
+    if (reg_type.IsPreciseReference() || concrete_method->IsFinal() ||
+        concrete_method->GetDeclaringClass()->IsFinal()) {
+      // If we knew exactly the class being dispatched upon, or if the target method cannot be
+      // overridden record the target to be used in the compiler driver.
+      if (pc_to_concrete_method_map.get() == NULL) {
+        pc_to_concrete_method_map.reset(new PcToConcreteMethodMap());
+      }
+      CompilerDriver::MethodReference concrete_ref(
+          concrete_method->GetDeclaringClass()->GetDexCache()->GetDexFile(),
+          concrete_method->GetDexMethodIndex());
+      pc_to_concrete_method_map->Put(dex_pc, concrete_ref);
     }
-
-  if (pc_to_concrete_method->size() == 0) {
-    delete pc_to_concrete_method;
-    return NULL ;
   }
-  return pc_to_concrete_method;
+  return pc_to_concrete_method_map.release();
 }
 
 const std::vector<uint8_t>* MethodVerifier::GenerateGcMap() {
@@ -3276,6 +3482,7 @@
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Failed to encode GC map (size=" << table_size << ")";
     return NULL;
   }
+  table->reserve(table_size);
   // Write table header
   table->push_back(format | ((ref_bitmap_bytes >> DexPcToReferenceMap::kRegMapFormatShift) &
                              ~DexPcToReferenceMap::kRegMapFormatMask));
@@ -3326,9 +3533,10 @@
   }
 }
 
-void MethodVerifier::SetDexGcMap(CompilerDriver::MethodReference ref, const std::vector<uint8_t>& gc_map) {
+void MethodVerifier::SetDexGcMap(CompilerDriver::MethodReference ref,
+                                 const std::vector<uint8_t>& gc_map) {
   {
-    MutexLock mu(Thread::Current(), *dex_gc_maps_lock_);
+    WriterMutexLock mu(Thread::Current(), *dex_gc_maps_lock_);
     DexGcMapTable::iterator it = dex_gc_maps_->find(ref);
     if (it != dex_gc_maps_->end()) {
       delete it->second;
@@ -3336,12 +3544,49 @@
     }
     dex_gc_maps_->Put(ref, &gc_map);
   }
-  CHECK(GetDexGcMap(ref) != NULL);
+  DCHECK(GetDexGcMap(ref) != NULL);
 }
 
-void  MethodVerifier::SetDevirtMap(CompilerDriver::MethodReference ref, const PcToConreteMethod* devirt_map) {
 
-  MutexLock mu(Thread::Current(), *devirt_maps_lock_);
+void  MethodVerifier::SetSafeCastMap(CompilerDriver::MethodReference ref,
+                                     const MethodSafeCastSet* cast_set) {
+  MutexLock mu(Thread::Current(), *safecast_map_lock_);
+  SafeCastMap::iterator it = safecast_map_->find(ref);
+  if (it != safecast_map_->end()) {
+    delete it->second;
+    safecast_map_->erase(it);
+  }
+
+  safecast_map_->Put(ref, cast_set);
+  CHECK(safecast_map_->find(ref) != safecast_map_->end());
+}
+
+bool MethodVerifier::IsSafeCast(CompilerDriver::MethodReference ref, uint32_t pc) {
+  MutexLock mu(Thread::Current(), *safecast_map_lock_);
+  SafeCastMap::const_iterator it = safecast_map_->find(ref);
+  if (it == safecast_map_->end()) {
+    return false;
+  }
+
+  // Look up the cast address in the set of safe casts
+  MethodVerifier::MethodSafeCastSet::const_iterator cast_it = it->second->find(pc);
+  return cast_it != it->second->end();
+}
+
+const std::vector<uint8_t>* MethodVerifier::GetDexGcMap(CompilerDriver::MethodReference ref) {
+  ReaderMutexLock mu(Thread::Current(), *dex_gc_maps_lock_);
+  DexGcMapTable::const_iterator it = dex_gc_maps_->find(ref);
+  if (it == dex_gc_maps_->end()) {
+    LOG(WARNING) << "Didn't find GC map for: " << PrettyMethod(ref.dex_method_index, *ref.dex_file);
+    return NULL;
+  }
+  CHECK(it->second != NULL);
+  return it->second;
+}
+
+void  MethodVerifier::SetDevirtMap(CompilerDriver::MethodReference ref,
+                                   const PcToConcreteMethodMap* devirt_map) {
+  WriterMutexLock mu(Thread::Current(), *devirt_maps_lock_);
   DevirtualizationMapTable::iterator it = devirt_maps_->find(ref);
   if (it != devirt_maps_->end()) {
     delete it->second;
@@ -3352,26 +3597,16 @@
   CHECK(devirt_maps_->find(ref) != devirt_maps_->end());
 }
 
-const std::vector<uint8_t>* MethodVerifier::GetDexGcMap(CompilerDriver::MethodReference ref) {
-  MutexLock mu(Thread::Current(), *dex_gc_maps_lock_);
-  DexGcMapTable::const_iterator it = dex_gc_maps_->find(ref);
-  if (it == dex_gc_maps_->end()) {
-    LOG(WARNING) << "Didn't find GC map for: " << PrettyMethod(ref.second, *ref.first);
-    return NULL;
-  }
-  CHECK(it->second != NULL);
-  return it->second;
-}
-
-const CompilerDriver::MethodReference* MethodVerifier::GetDevirtMap(CompilerDriver::MethodReference ref, uint32_t pc) {
-  MutexLock mu(Thread::Current(), *devirt_maps_lock_);
+const CompilerDriver::MethodReference* MethodVerifier::GetDevirtMap(const CompilerDriver::MethodReference& ref,
+                                                                    uint32_t dex_pc) {
+  ReaderMutexLock mu(Thread::Current(), *devirt_maps_lock_);
   DevirtualizationMapTable::const_iterator it = devirt_maps_->find(ref);
   if (it == devirt_maps_->end()) {
     return NULL;
   }
 
   // Look up the PC in the map, get the concrete method to execute and return its reference.
-  MethodVerifier::PcToConreteMethod::const_iterator pc_to_concrete_method = it->second->find(pc);
+  MethodVerifier::PcToConcreteMethodMap::const_iterator pc_to_concrete_method = it->second->find(dex_pc);
   if(pc_to_concrete_method != it->second->end()) {
     return &(pc_to_concrete_method->second);
   } else {
@@ -3423,26 +3658,36 @@
   return result;
 }
 
-Mutex* MethodVerifier::dex_gc_maps_lock_ = NULL;
+ReaderWriterMutex* MethodVerifier::dex_gc_maps_lock_ = NULL;
 MethodVerifier::DexGcMapTable* MethodVerifier::dex_gc_maps_ = NULL;
 
-Mutex* MethodVerifier::devirt_maps_lock_ = NULL;
+Mutex* MethodVerifier::safecast_map_lock_ = NULL;
+MethodVerifier::SafeCastMap* MethodVerifier::safecast_map_ = NULL;
+
+ReaderWriterMutex* MethodVerifier::devirt_maps_lock_ = NULL;
 MethodVerifier::DevirtualizationMapTable* MethodVerifier::devirt_maps_ = NULL;
 
 Mutex* MethodVerifier::rejected_classes_lock_ = NULL;
 MethodVerifier::RejectedClassesTable* MethodVerifier::rejected_classes_ = NULL;
 
 void MethodVerifier::Init() {
-  dex_gc_maps_lock_ = new Mutex("verifier GC maps lock");
+  dex_gc_maps_lock_ = new ReaderWriterMutex("verifier GC maps lock");
   Thread* self = Thread::Current();
   {
-    MutexLock mu(self, *dex_gc_maps_lock_);
+    WriterMutexLock mu(self, *dex_gc_maps_lock_);
     dex_gc_maps_ = new MethodVerifier::DexGcMapTable;
   }
 
-  devirt_maps_lock_ = new Mutex("verifier Devirtualization lock");
+  safecast_map_lock_ = new Mutex("verifier Cast Elision lock");
   {
-    MutexLock mu(self, *devirt_maps_lock_);
+    MutexLock mu(self, *safecast_map_lock_);
+    safecast_map_ = new MethodVerifier::SafeCastMap();
+  }
+
+  devirt_maps_lock_ = new ReaderWriterMutex("verifier Devirtualization lock");
+
+  {
+    WriterMutexLock mu(self, *devirt_maps_lock_);
     devirt_maps_ = new MethodVerifier::DevirtualizationMapTable();
   }
 
@@ -3457,7 +3702,7 @@
 void MethodVerifier::Shutdown() {
   Thread* self = Thread::Current();
   {
-    MutexLock mu(self, *dex_gc_maps_lock_);
+    WriterMutexLock mu(self, *dex_gc_maps_lock_);
     STLDeleteValues(dex_gc_maps_);
     delete dex_gc_maps_;
     dex_gc_maps_ = NULL;
@@ -3466,7 +3711,7 @@
   dex_gc_maps_lock_ = NULL;
 
   {
-    MutexLock mu(self, *devirt_maps_lock_);
+    WriterMutexLock mu(self, *devirt_maps_lock_);
     STLDeleteValues(devirt_maps_);
     delete devirt_maps_;
     devirt_maps_ = NULL;
diff --git a/src/verifier/method_verifier.h b/src/verifier/method_verifier.h
index ab7e3cc..198d8cb 100644
--- a/src/verifier/method_verifier.h
+++ b/src/verifier/method_verifier.h
@@ -187,9 +187,15 @@
   static const std::vector<uint8_t>* GetDexGcMap(CompilerDriver::MethodReference ref)
       LOCKS_EXCLUDED(dex_gc_maps_lock_);
 
-  static const CompilerDriver::MethodReference* GetDevirtMap(CompilerDriver::MethodReference ref, uint32_t pc)
+  static const CompilerDriver::MethodReference* GetDevirtMap(const CompilerDriver::MethodReference& ref,
+                                                             uint32_t dex_pc)
       LOCKS_EXCLUDED(devirt_maps_lock_);
 
+  // Returns true if the cast can statically be verified to be redundant
+  // by using the check-cast elision peephole optimization in the verifier
+  static bool IsSafeCast(CompilerDriver::MethodReference ref, uint32_t pc)
+        LOCKS_EXCLUDED(safecast_map_lock_);
+
   // Fills 'monitor_enter_dex_pcs' with the dex pcs of the monitor-enter instructions corresponding
   // to the locks held at 'dex_pc' in 'm'.
   static void FindLocksAtDexPc(mirror::AbstractMethod* m, uint32_t dex_pc,
@@ -447,19 +453,18 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Perform verification of a new array instruction
-  void VerifyNewArray(const DecodedInstruction& dec_insn, bool is_filled,
-                      bool is_range)
+  void VerifyNewArray(const Instruction* inst, bool is_filled, bool is_range)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Perform verification of an aget instruction. The destination register's type will be set to
   // be that of component type of the array unless the array type is unknown, in which case a
   // bottom type inferred from the type of instruction is used. is_primitive is false for an
   // aget-object.
-  void VerifyAGet(const DecodedInstruction& insn, const RegType& insn_type,
+  void VerifyAGet(const Instruction* inst, const RegType& insn_type,
                   bool is_primitive) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Perform verification of an aput instruction.
-  void VerifyAPut(const DecodedInstruction& insn, const RegType& insn_type,
+  void VerifyAPut(const Instruction* inst, const RegType& insn_type,
                   bool is_primitive) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Lookup instance field and fail for resolution violations
@@ -470,12 +475,12 @@
   mirror::Field* GetStaticField(int field_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Perform verification of an iget or sget instruction.
-  void VerifyISGet(const DecodedInstruction& insn, const RegType& insn_type,
+  void VerifyISGet(const Instruction* inst, const RegType& insn_type,
                    bool is_primitive, bool is_static)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Perform verification of an iput or sput instruction.
-  void VerifyISPut(const DecodedInstruction& insn, const RegType& insn_type,
+  void VerifyISPut(const Instruction* inst, const RegType& insn_type,
                    bool is_primitive, bool is_static)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -522,8 +527,9 @@
    * Returns the resolved method on success, NULL on failure (with *failure
    * set appropriately).
    */
-  mirror::AbstractMethod* VerifyInvocationArgs(const DecodedInstruction& dec_insn,
-                               MethodType method_type, bool is_range, bool is_super)
+  mirror::AbstractMethod* VerifyInvocationArgs(const Instruction* inst,
+                                               MethodType method_type,
+                                               bool is_range, bool is_super)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   /*
@@ -574,23 +580,36 @@
   InstructionFlags* CurrentInsnFlags();
 
   // All the GC maps that the verifier has created
-  typedef SafeMap<const CompilerDriver::MethodReference, const std::vector<uint8_t>*> DexGcMapTable;
-  static Mutex* dex_gc_maps_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  typedef SafeMap<const CompilerDriver::MethodReference, const std::vector<uint8_t>*,
+      CompilerDriver::MethodReferenceComparator> DexGcMapTable;
+  static ReaderWriterMutex* dex_gc_maps_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   static DexGcMapTable* dex_gc_maps_ GUARDED_BY(dex_gc_maps_lock_);
   static void SetDexGcMap(CompilerDriver::MethodReference ref, const std::vector<uint8_t>& dex_gc_map)
       LOCKS_EXCLUDED(dex_gc_maps_lock_);
 
 
+  // Cast elision types.
+  typedef std::set<uint32_t> MethodSafeCastSet;
+  typedef SafeMap<const CompilerDriver::MethodReference, const MethodSafeCastSet*,
+      CompilerDriver::MethodReferenceComparator> SafeCastMap;
+  MethodVerifier::MethodSafeCastSet* GenerateSafeCastSet()
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static void SetSafeCastMap(CompilerDriver::MethodReference ref, const MethodSafeCastSet* mscs);
+      LOCKS_EXCLUDED(safecast_map_lock_);
+  static Mutex* safecast_map_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  static SafeCastMap* safecast_map_ GUARDED_BY(safecast_map_lock_);
+
   // Devirtualization map.
-  typedef SafeMap<const uint32_t, CompilerDriver::MethodReference> PcToConreteMethod;
-  typedef SafeMap<const CompilerDriver::MethodReference, const PcToConreteMethod*>
-      DevirtualizationMapTable;
-  MethodVerifier::PcToConreteMethod* GenerateDevirtMap()
+  typedef SafeMap<const uint32_t, CompilerDriver::MethodReference> PcToConcreteMethodMap;
+  typedef SafeMap<const CompilerDriver::MethodReference, const PcToConcreteMethodMap*,
+      CompilerDriver::MethodReferenceComparator> DevirtualizationMapTable;
+  MethodVerifier::PcToConcreteMethodMap* GenerateDevirtMap()
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static Mutex* devirt_maps_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  static ReaderWriterMutex* devirt_maps_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   static DevirtualizationMapTable* devirt_maps_ GUARDED_BY(devirt_maps_lock_);
-  static void SetDevirtMap(CompilerDriver::MethodReference ref, const PcToConreteMethod* pc_method_map);
+  static void SetDevirtMap(CompilerDriver::MethodReference ref,
+                           const PcToConcreteMethodMap* pc_method_map)
         LOCKS_EXCLUDED(devirt_maps_lock_);
   typedef std::set<CompilerDriver::ClassReference> RejectedClassesTable;
   static Mutex* rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
@@ -613,20 +632,20 @@
   // Storage for the register status we're saving for later.
   UniquePtr<RegisterLine> saved_line_;
 
-  uint32_t dex_method_idx_;  // The method we're working on.
+  const uint32_t dex_method_idx_;  // The method we're working on.
   // Its object representation if known.
-  mirror::AbstractMethod* foo_method_ GUARDED_BY(Locks::mutator_lock_);
-  uint32_t method_access_flags_;  // Method's access flags.
-  const DexFile* dex_file_;  // The dex file containing the method.
+  mirror::AbstractMethod* mirror_method_ GUARDED_BY(Locks::mutator_lock_);
+  const uint32_t method_access_flags_;  // Method's access flags.
+  const DexFile* const dex_file_;  // The dex file containing the method.
   // The dex_cache for the declaring class of the method.
   mirror::DexCache* dex_cache_ GUARDED_BY(Locks::mutator_lock_);
   // The class loader for the declaring class of the method.
   mirror::ClassLoader* class_loader_ GUARDED_BY(Locks::mutator_lock_);
-  uint32_t class_def_idx_;  // The class def index of the declaring class of the method.
-  const DexFile::CodeItem* code_item_;  // The code item containing the code for the method.
+  const uint32_t class_def_idx_;  // The class def index of the declaring class of the method.
+  const DexFile::CodeItem* const code_item_;  // The code item containing the code for the method.
+  const RegType* declaring_class_;  // Lazily computed reg type of the method's declaring class.
   // Instruction widths and flags, one entry per code unit.
   UniquePtr<InstructionFlags[]> insn_flags_;
-
   // The dex PC of a FindLocksAtDexPc request, -1 otherwise.
   uint32_t interesting_dex_pc_;
   // The container into which FindLocksAtDexPc should write the registers containing held locks,
diff --git a/src/verifier/reg_type.cc b/src/verifier/reg_type.cc
index 32679f6..1c61a29 100644
--- a/src/verifier/reg_type.cc
+++ b/src/verifier/reg_type.cc
@@ -25,6 +25,7 @@
 #include "mirror/object_array-inl.h"
 #include "object_utils.h"
 #include "reg_type_cache-inl.h"
+#include "scoped_thread_state_change.h"
 
 #include <limits>
 #include <sstream>
@@ -32,7 +33,6 @@
 namespace art {
 namespace verifier {
 
-static const bool kIsDebugBuild = false;
 UndefinedType* UndefinedType::instance_ = NULL;
 ConflictType* ConflictType::instance_ = NULL;
 BooleanType* BooleanType::instance = NULL;
@@ -46,6 +46,41 @@
 DoubleHiType* DoubleHiType::instance_ = NULL;
 IntegerType* IntegerType::instance_ = NULL;
 
+int32_t RegType::ConstantValue() const {
+  ScopedObjectAccess soa(Thread::Current());
+  LOG(FATAL) << "Unexpected call to ConstantValue: " << *this;
+  return 0;
+}
+
+int32_t RegType::ConstantValueLo() const {
+  ScopedObjectAccess soa(Thread::Current());
+  LOG(FATAL) << "Unexpected call to ConstantValueLo: " << *this;
+  return 0;
+}
+
+int32_t RegType::ConstantValueHi() const {
+  ScopedObjectAccess soa(Thread::Current());
+  LOG(FATAL) << "Unexpected call to ConstantValueHi: " << *this;
+  return 0;
+}
+
+PrimitiveType::PrimitiveType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+    : RegType(klass, descriptor, cache_id) {
+  CHECK(klass != NULL);
+  CHECK(!descriptor.empty());
+}
+
+Cat1Type::Cat1Type(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+    : PrimitiveType(klass, descriptor, cache_id) {
+}
+
+Cat2Type::Cat2Type(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+    : PrimitiveType(klass, descriptor, cache_id) {
+}
+
 std::string PreciseConstType::Dump() const {
   std::stringstream result;
   uint32_t val = ConstantValue();
@@ -70,36 +105,44 @@
 std::string ConflictType::Dump() const {
     return "Conflict";
 }
+
 std::string ByteType::Dump() const {
   return "Byte";
 }
+
 std::string ShortType::Dump() const {
   return "short";
 }
+
 std::string CharType::Dump() const {
   return "Char";
 }
+
 std::string FloatType::Dump() const {
   return "float";
 }
+
 std::string LongLoType::Dump() const {
   return "long (Low Half)";
 }
+
 std::string LongHiType::Dump() const {
   return "long (High Half)";
 }
+
 std::string DoubleLoType::Dump() const {
   return "Double (Low Half)";
 }
+
 std::string DoubleHiType::Dump() const {
   return "Double (High Half)";
 }
+
 std::string IntegerType::Dump() const {
     return "Integer";
 }
 
-
-DoubleHiType* DoubleHiType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+DoubleHiType* DoubleHiType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                            uint16_t cache_id) {
   if (instance_ == NULL) {
     instance_ = new DoubleHiType(klass, descriptor, cache_id);
@@ -119,7 +162,7 @@
   }
 }
 
-DoubleLoType* DoubleLoType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+DoubleLoType* DoubleLoType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                            uint16_t cache_id) {
   if (instance_ == NULL) {
     instance_ = new DoubleLoType(klass, descriptor, cache_id);
@@ -139,7 +182,7 @@
   }
 }
 
-LongLoType* LongLoType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+LongLoType* LongLoType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                        uint16_t cache_id) {
   if (instance_ == NULL) {
     instance_ = new LongLoType(klass, descriptor, cache_id);
@@ -147,7 +190,7 @@
   return instance_;
 }
 
-LongHiType* LongHiType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+LongHiType* LongHiType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                        uint16_t cache_id) {
   if (instance_ == NULL) {
     instance_ = new LongHiType(klass, descriptor, cache_id);
@@ -179,9 +222,8 @@
   }
 }
 
-FloatType* FloatType::CreateInstance(mirror::Class* klass, std::string& descriptor,
-                                     uint16_t cache_id)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+FloatType* FloatType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
+                                     uint16_t cache_id) {
   if (instance_ == NULL) {
     instance_ = new FloatType(klass, descriptor, cache_id);
   }
@@ -199,17 +241,19 @@
   }
 }
 
-CharType* CharType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+CharType* CharType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                    uint16_t cache_id) {
   if (instance_ == NULL) {
     instance_ = new CharType(klass, descriptor, cache_id);
   }
   return instance_;
 }
+
 CharType* CharType::GetInstance() {
   CHECK(instance_ != NULL);
   return instance_;
 }
+
 void CharType::Destroy() {
   if (instance_ != NULL) {
     delete instance_;
@@ -217,81 +261,94 @@
   }
 }
 
-ShortType* ShortType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+ShortType* ShortType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                      uint16_t cache_id) {
   if (instance_ == NULL) {
     instance_ = new ShortType(klass, descriptor, cache_id);
   }
   return instance_;
 }
+
 ShortType* ShortType::GetInstance() {
   CHECK(instance_ != NULL);
   return instance_;
 }
+
 void ShortType::Destroy() {
   if (instance_ != NULL) {
     delete instance_;
     instance_ = NULL;
   }
 }
-ByteType* ByteType::CreateInstance(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+
+ByteType* ByteType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
+                                   uint16_t cache_id) {
   if (instance_ == NULL) {
     instance_ = new ByteType(klass, descriptor, cache_id);
   }
   return instance_;
 }
+
 ByteType* ByteType::GetInstance() {
   CHECK(instance_ != NULL);
   return instance_;
 }
+
 void ByteType::Destroy() {
   if (instance_ != NULL) {
     delete instance_;
     instance_ = NULL;
   }
 }
-IntegerType* IntegerType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+
+IntegerType* IntegerType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                          uint16_t cache_id) {
   if (instance_ == NULL) {
     instance_ = new IntegerType(klass, descriptor, cache_id);
   }
   return instance_;
 }
+
 IntegerType* IntegerType::GetInstance() {
   CHECK(instance_ != NULL);
   return instance_;
 }
+
 void IntegerType::Destroy() {
   if (instance_ != NULL) {
     delete instance_;
     instance_ = NULL;
   }
 }
-ConflictType* ConflictType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+
+ConflictType* ConflictType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                            uint16_t cache_id) {
   if (instance_ == NULL) {
     instance_ = new ConflictType(klass, descriptor, cache_id);
   }
   return instance_;
 }
+
 ConflictType* ConflictType::GetInstance() {
   CHECK(instance_ != NULL);
   return instance_;
 }
+
 void ConflictType::Destroy() {
   if (instance_ != NULL) {
     delete instance_;
     instance_ = NULL;
   }
 }
-BooleanType* BooleanType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+
+BooleanType* BooleanType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                          uint16_t cache_id) {
   if (BooleanType::instance == NULL) {
     instance = new BooleanType(klass, descriptor, cache_id);
   }
   return BooleanType::instance;
 }
+
 BooleanType* BooleanType::GetInstance() {
   CHECK(BooleanType::instance != NULL);
   return BooleanType::instance;
@@ -307,23 +364,33 @@
 std::string UndefinedType::Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   return "Undefined";
 }
-UndefinedType* UndefinedType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+
+UndefinedType* UndefinedType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                              uint16_t cache_id) {
   if (instance_ == NULL) {
     instance_ = new UndefinedType(klass, descriptor, cache_id);
   }
   return instance_;
 }
+
 UndefinedType* UndefinedType::GetInstance() {
   CHECK(instance_ != NULL);
   return instance_;
 }
+
 void UndefinedType::Destroy() {
   if (instance_ != NULL) {
     delete instance_;
     instance_ = NULL;
   }
 }
+
+PreciseReferenceType::PreciseReferenceType(mirror::Class* klass, const std::string& descriptor,
+                                           uint16_t cache_id)
+    : RegType(klass, descriptor, cache_id) {
+  DCHECK(klass->IsInstantiable());
+}
+
 std::string UnresolvedMergedType::Dump() const {
   std::stringstream result;
   std::set<uint16_t> types = GetMergedTypes();
@@ -338,6 +405,7 @@
   result << ")";
   return result.str();
 }
+
 std::string UnresolvedSuperClass::Dump() const {
   std::stringstream result;
   uint16_t super_type_id = GetUnresolvedSuperClassChildId();
@@ -358,7 +426,7 @@
   return result.str();
 }
 
-std::string UnresolvedUninitialisedThisRefType::Dump() const {
+std::string UnresolvedUninitializedThisRefType::Dump() const {
   std::stringstream result;
   result << "Unresolved And Uninitialized This Reference" << PrettyDescriptor(GetDescriptor());
   return result.str();
@@ -376,13 +444,14 @@
   return result.str();
 }
 
-std::string UninitialisedReferenceType::Dump() const {
+std::string UninitializedReferenceType::Dump() const {
   std::stringstream result;
   result << "Uninitialized Reference" << ": " << PrettyDescriptor(GetClass());
   result << " Allocation PC: " << GetAllocationPc();
   return result.str();
 }
-std::string UninitialisedThisReferenceType::Dump() const {
+
+std::string UninitializedThisReferenceType::Dump() const {
   std::stringstream result;
   result << "Uninitialized This Reference" << ": " << PrettyDescriptor(GetClass());
   result << "Allocation PC: " << GetAllocationPc();
@@ -459,77 +528,8 @@
   return result.str();
 }
 
-BooleanType::BooleanType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      : RegType(klass, descriptor, cache_id) {
-}
-
-ConflictType::ConflictType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
-}
-
-ByteType::ByteType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
-}
-
-ShortType::ShortType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
-}
-
-CharType::CharType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
-}
-
-IntegerType::IntegerType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
-}
-
-ConstantType::ConstantType(uint32_t constat, uint16_t cache_id)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_): RegType(NULL, "", cache_id), constant_(constat) {
-}
-
-ReferenceType::ReferenceType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
-}
-
-PreciseReferenceType::PreciseReferenceType(mirror::Class* klass, std::string& descriptor,
-                                           uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
-  DCHECK(klass->IsInstantiable());
-}
-
-UnresolvedUninitialisedThisRefType::UnresolvedUninitialisedThisRefType(std::string& descriptor,
-                                                                       uint16_t cache_id)
-    : UninitializedType(NULL, descriptor, 0, cache_id) {
-}
-
-UnresolvedUninitializedRefType::UnresolvedUninitializedRefType( std::string& descriptor,
-                                                         uint32_t allocation_pc, uint16_t cache_id)
-    : UninitializedType(NULL, descriptor, allocation_pc, cache_id) {
-}
-
-UninitialisedReferenceType::UninitialisedReferenceType(mirror::Class* klass,
-                                std::string& descriptor, uint32_t allocation_pc, uint16_t cache_id)
-    : UninitializedType(klass, descriptor, allocation_pc, cache_id) {
-}
-
-LongHiType::LongHiType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
-}
-
-FloatType::FloatType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
-}
-
-DoubleLoType::DoubleLoType(mirror::Class* klass,  std::string& descriptor, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
-}
-
-DoubleHiType::DoubleHiType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
-}
-
-LongLoType::LongLoType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
+ConstantType::ConstantType(uint32_t constant, uint16_t cache_id)
+    : RegType(NULL, "", cache_id), constant_(constant) {
 }
 
 const RegType& UndefinedType::Merge(const RegType& incoming_type, RegTypeCache* reg_types) const
@@ -575,6 +575,17 @@
   }
 }
 
+bool UninitializedType::IsUninitializedTypes() const {
+  return true;
+}
+
+bool UninitializedType::IsNonZeroReferenceTypes() const {
+  return true;
+}
+
+bool UnresolvedType::IsNonZeroReferenceTypes() const {
+  return true;
+}
 std::set<uint16_t> UnresolvedMergedType::GetMergedTypes() const {
   std::pair<uint16_t, uint16_t> refs = GetTopMergedTypes();
   const RegType& _left(reg_type_cache_->GetFromId(refs.first));
@@ -612,7 +623,7 @@
     if (super_klass != NULL) {
       // A super class of a precise type isn't precise as a precise type indicates the register
       // holds exactly that type.
-      return cache->FromClass(super_klass, false);
+      return cache->FromClass(ClassHelper(super_klass).GetDescriptor(), super_klass, false);
     } else {
       return cache->Zero();
     }
@@ -697,62 +708,72 @@
   : ConstantType(constat, cache_id) {
 }
 
-bool RegType::IsAssignableFrom(const RegType& src) const {
-  if (Equals(src)) {
+static bool AssignableFrom(const RegType& lhs, const RegType& rhs, bool strict)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (lhs.Equals(rhs)) {
     return true;
   } else {
-    if (IsBoolean()) {
-      return src.IsBooleanTypes();
-    } else if (IsByte()) {
-      return src.IsByteTypes();
-    } else if (IsShort()) {
-      return src.IsShortTypes();
-    } else if (IsChar()) {
-      return src.IsCharTypes();
-    } else if (IsInteger()) {
-      return src.IsIntegralTypes();
-    } else if (IsFloat()) {
-      return src.IsFloatTypes();
-    } else if (IsLongLo()) {
-      return src.IsLongTypes();
-    } else if (IsDoubleLo()) {
-      return src.IsDoubleTypes();
+    if (lhs.IsBoolean()) {
+      return rhs.IsBooleanTypes();
+    } else if (lhs.IsByte()) {
+      return rhs.IsByteTypes();
+    } else if (lhs.IsShort()) {
+      return rhs.IsShortTypes();
+    } else if (lhs.IsChar()) {
+      return rhs.IsCharTypes();
+    } else if (lhs.IsInteger()) {
+      return rhs.IsIntegralTypes();
+    } else if (lhs.IsFloat()) {
+      return rhs.IsFloatTypes();
+    } else if (lhs.IsLongLo()) {
+      return rhs.IsLongTypes();
+    } else if (lhs.IsDoubleLo()) {
+      return rhs.IsDoubleTypes();
     } else {
-      if (!IsReferenceTypes()) {
-        LOG(FATAL) << "Unexpected register type in 4bleFrom: '" << src << "'";
+      CHECK(lhs.IsReferenceTypes())
+          << "Unexpected register type in IsAssignableFrom: '"
+          << lhs << "' := '" << rhs << "'";
+      if (rhs.IsZero()) {
+        return true;  // All reference types can be assigned null.
+      } else if (!rhs.IsReferenceTypes()) {
+        return false;  // Expect rhs to be a reference type.
+      } else if (lhs.IsJavaLangObject()) {
+        return true;  // All reference types can be assigned to Object.
+      } else if (!strict && !lhs.IsUnresolvedTypes() && lhs.GetClass()->IsInterface()) {
+        // If we're not strict allow assignment to any interface, see comment in ClassJoin.
+        return true;
+      } else if (lhs.IsJavaLangObjectArray()) {
+        return rhs.IsObjectArrayTypes();  // All reference arrays may be assigned to Object[]
+      } else if (lhs.HasClass() && rhs.HasClass() &&
+                 lhs.GetClass()->IsAssignableFrom(rhs.GetClass())) {
+        // We're assignable from the Class point-of-view.
+        return true;
+      } else {
+        // Unresolved types are only assignable for null and equality.
+        return false;
       }
-      if (src.IsZero()) {
-        return true;  // all reference types can be assigned null
-      } else if (!src.IsReferenceTypes()) {
-        return false;  // expect src to be a reference type
-      } else if (IsJavaLangObject()) {
-        return true;  // all reference types can be assigned to Object
-      } else if (!IsUnresolvedTypes() && GetClass()->IsInterface()) {
-          return true;  // We allow assignment to any interface, see comment in ClassJoin
-        } else if (IsJavaLangObjectArray()) {
-          return src.IsObjectArrayTypes();  // All reference arrays may be assigned to Object[]
-        } else if (!IsUnresolvedTypes() && !src.IsUnresolvedTypes() &&
-                   GetClass()->IsAssignableFrom(src.GetClass())) {
-          // We're assignable from the Class point-of-view
-          return true;
-        } else if (IsUnresolvedTypes()) {
-          // Unresolved types are only assignable for null, Object and equality.
-          return (src.IsZero() || src.IsJavaLangObject());
-        } else {
-          return false;
-        }
     }
   }
 }
 
+bool RegType::IsAssignableFrom(const RegType& src) const {
+  return AssignableFrom(*this, src, false);
+}
+
+bool RegType::IsStrictlyAssignableFrom(const RegType& src) const {
+  return AssignableFrom(*this, src, true);
+}
+
 int32_t ConstantType::ConstantValue() const {
   DCHECK(IsConstantTypes());
   return constant_;
 }
+
 int32_t ConstantType::ConstantValueLo() const {
   DCHECK(IsConstantLo());
   return constant_;
 }
+
 int32_t ConstantType::ConstantValueHi() const {
   if (IsConstantHi() || IsPreciseConstantHi() || IsImpreciseConstantHi()) {
     return constant_;
@@ -761,6 +782,7 @@
     return 0;
   }
 }
+
 static const RegType& SelectNonConstant(const RegType& a, const RegType& b) {
   return a.IsConstant() ? b : a;
 }
@@ -884,7 +906,7 @@
       } else if (c2 == join_class && !incoming_type.IsPreciseReference()) {
         return incoming_type;
       } else {
-        return reg_types->FromClass(join_class, false);
+        return reg_types->FromClass(ClassHelper(join_class).GetDescriptor(), join_class, false);
       }
     }
   } else {
@@ -949,33 +971,22 @@
     CHECK(descriptor_.empty()) << *this;
     CHECK(klass_ == NULL) << *this;
   }
+  if (klass_ != NULL) {
+    CHECK(!descriptor_.empty()) << *this;
+  }
 }
 
-UninitializedType::UninitializedType(mirror::Class* klass, std::string& descriptor,
-                                     uint32_t allocation_pc, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id), allocation_pc_(allocation_pc) {
+void UninitializedThisReferenceType::CheckInvariants() const {
+  CHECK_EQ(GetAllocationPc(), 0U) << *this;
 }
 
-void UninitializedType::CheckInvariants() const {
-  CHECK_EQ(allocation_pc_, 0U) << *this;
-}
-
-void UninitialisedThisReferenceType::CheckInvariants() const {
-  UninitializedType::CheckInvariants();
-}
-
-UninitialisedThisReferenceType::UninitialisedThisReferenceType(mirror::Class* klass,
-  std::string& descriptor, uint16_t cache_id) : UninitializedType(klass, descriptor, 0, cache_id) {
-}
-
-void UnresolvedUninitialisedThisRefType::CheckInvariants() const {
-  UninitializedType::CheckInvariants();
+void UnresolvedUninitializedThisRefType::CheckInvariants() const {
+  CHECK_EQ(GetAllocationPc(), 0U) << *this;
   CHECK(!descriptor_.empty()) << *this;
   CHECK(klass_ == NULL) << *this;
 }
 
 void UnresolvedUninitializedRefType::CheckInvariants() const {
-  UninitializedType::CheckInvariants();
   CHECK(!descriptor_.empty()) << *this;
   CHECK(klass_ == NULL) << *this;
 }
diff --git a/src/verifier/reg_type.h b/src/verifier/reg_type.h
index 7c42536..9ac0eca 100644
--- a/src/verifier/reg_type.h
+++ b/src/verifier/reg_type.h
@@ -18,6 +18,7 @@
 #define ART_SRC_VERIFIER_REG_TYPE_H_
 
 #include "base/macros.h"
+#include "globals.h"
 #include "primitive.h"
 
 #include "jni.h"
@@ -39,105 +40,43 @@
  */
 class RegType {
  public:
-  // The high half that corresponds to this low half
-  const RegType& HighHalf(RegTypeCache* cache) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  inline virtual bool IsUndefined() const {
-    return false;
-  }
-  inline virtual bool IsConflict() const {
-    return false;
-  }
-  inline virtual bool IsBoolean() const {
-    return false;
-  }
-  inline virtual bool IsByte() const {
-    return false;
-  }
-  inline virtual bool IsChar() const {
-    return false;
-  }
-  inline virtual bool IsShort() const {
-    return false;
-  }
-  inline virtual bool IsInteger() const {
-    return false;
-  }
-  inline virtual bool IsLongLo() const {
-    return false;
-  }
-  inline virtual bool IsLongHi() const {
-    return false;
-  }
-  inline virtual bool IsFloat() const {
-    return false;
-  }
-  inline virtual bool IsDouble() const {
-    return false;
-  }
-  inline virtual bool IsDoubleLo() const {
-    return false;
-  }
-  inline virtual bool IsDoubleHi() const {
-    return false;
-  }
-  inline virtual bool IsUnresolvedReference() const {
-    return false;
-  }
-  inline virtual bool IsUninitializedReference() const {
-    return false;
-  }
-  inline virtual bool IsUninitializedThisReference() const {
-    return false;
-  }
-  inline virtual bool IsUnresolvedAndUninitializedReference() const {
-    return false;
-  }
-  inline virtual bool IsUnresolvedAndUninitializedThisReference() const {
-    return false;
-  }
-  inline virtual bool IsUnresolvedMergedReference() const {
-    return false;
-  }
-  inline virtual bool IsUnresolvedSuperClass() const {
-    return false;
-  }
-  inline virtual bool IsReference() const {
-    return false;
-  }
-  inline virtual bool IsPreciseReference() const {
-    return false;
-  }
-  inline virtual bool IsPreciseConstant() const {
-    return false;
-  }
-  inline virtual bool IsPreciseConstantLo() const {
-    return false;
-  }
-  inline virtual bool IsPreciseConstantHi() const {
-    return false;
-  }
-  inline virtual bool IsImpreciseConstantLo() const {
-    return false;
-  }
-  inline virtual bool IsImpreciseConstantHi() const {
-    return false;
-  }
-  virtual bool IsImpreciseConstant() const {
-    return false;
-  }
-
-  inline virtual bool IsConstantTypes() const {
-    return false;
-  }
+  virtual bool IsUndefined() const { return false; }
+  virtual bool IsConflict() const { return false; }
+  virtual bool IsBoolean() const { return false; }
+  virtual bool IsByte() const { return false; }
+  virtual bool IsChar() const { return false; }
+  virtual bool IsShort() const { return false; }
+  virtual bool IsInteger() const { return false; }
+  virtual bool IsLongLo() const { return false; }
+  virtual bool IsLongHi() const { return false; }
+  virtual bool IsFloat() const { return false; }
+  virtual bool IsDouble() const { return false; }
+  virtual bool IsDoubleLo() const { return false; }
+  virtual bool IsDoubleHi() const { return false; }
+  virtual bool IsUnresolvedReference() const { return false; }
+  virtual bool IsUninitializedReference() const { return false; }
+  virtual bool IsUninitializedThisReference() const { return false; }
+  virtual bool IsUnresolvedAndUninitializedReference() const { return false; }
+  virtual bool IsUnresolvedAndUninitializedThisReference() const { return false; }
+  virtual bool IsUnresolvedMergedReference() const { return false; }
+  virtual bool IsUnresolvedSuperClass() const { return false; }
+  virtual bool IsReference() const { return false; }
+  virtual bool IsPreciseReference() const { return false; }
+  virtual bool IsPreciseConstant() const { return false; }
+  virtual bool IsPreciseConstantLo() const { return false; }
+  virtual bool IsPreciseConstantHi() const { return false; }
+  virtual bool IsImpreciseConstantLo() const { return false; }
+  virtual bool IsImpreciseConstantHi() const { return false; }
+  virtual bool IsImpreciseConstant() const { return false; }
+  virtual bool IsConstantTypes() const { return false; }
   bool IsConstant() const {
-    return (IsPreciseConstant() || IsImpreciseConstant());
+    return IsPreciseConstant() || IsImpreciseConstant();
   }
   bool IsConstantLo() const {
-    return (IsPreciseConstantLo() || IsImpreciseConstantLo());
+    return IsPreciseConstantLo() || IsImpreciseConstantLo();
   }
   bool IsPrecise() const {
-    return (IsPreciseConstantLo() || IsPreciseConstant() ||
-            IsPreciseConstantHi());
+    return IsPreciseConstantLo() || IsPreciseConstant() || IsPreciseConstantHi();
   }
   bool IsLongConstant() const {
     return IsConstantLo();
@@ -148,11 +87,7 @@
   bool IsLongConstantHigh() const {
     return IsConstantHi();
   }
-  bool IsUninitializedTypes() const {
-    return IsUninitializedReference() || IsUninitializedThisReference() ||
-           IsUnresolvedAndUninitializedReference() ||
-           IsUnresolvedAndUninitializedThisReference();
-  }
+  virtual bool IsUninitializedTypes() const { return false; }
   bool IsUnresolvedTypes() const {
     return IsUnresolvedReference() || IsUnresolvedAndUninitializedReference() ||
            IsUnresolvedAndUninitializedThisReference() ||
@@ -170,7 +105,7 @@
   bool IsLongOrDoubleTypes() const {
     return IsLowHalf();
   }
-  // Check this is the low half, and that type_h is its matching high-half
+  // Check this is the low half, and that type_h is its matching high-half.
   inline bool CheckWidePair(const RegType& type_h) const {
     if (IsLowHalf()) {
       return ((IsPreciseConstantLo() && type_h.IsPreciseConstantHi()) ||
@@ -182,37 +117,36 @@
     }
     return false;
   }
+  // The high half that corresponds to this low half
+  const RegType& HighHalf(RegTypeCache* cache) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   bool IsConstantBoolean() const {
     return IsConstant() && (ConstantValue() >= 0) && (ConstantValue() <= 1);
   }
-  inline virtual bool IsConstantChar() const {
+  virtual bool IsConstantChar() const {
     return false;
   }
-  inline virtual bool IsConstantByte() const {
+  virtual bool IsConstantByte() const {
     return false;
   }
-  inline virtual bool IsConstantShort() const {
+  virtual bool IsConstantShort() const {
     return false;
   }
-  inline virtual bool IsOne() const {
+  virtual bool IsOne() const {
     return false;
   }
-  inline virtual bool IsZero() const {
+  virtual bool IsZero() const {
     return false;
   }
   bool IsReferenceTypes() const {
     return IsNonZeroReferenceTypes() || IsZero();
   }
-  bool IsNonZeroReferenceTypes() const {
-    return IsReference() || IsPreciseReference() ||
-           IsUninitializedReference() || IsUninitializedThisReference() ||
-           IsUnresolvedReference() || IsUnresolvedAndUninitializedReference() ||
-           IsUnresolvedAndUninitializedThisReference() ||
-           IsUnresolvedMergedReference() || IsUnresolvedSuperClass();
+  virtual bool IsNonZeroReferenceTypes() const {
+    return false;
   }
   bool IsCategory1Types() const {
-    return (IsChar() || IsInteger() || IsFloat() || IsConstant() || IsByte() ||
-        IsShort() || IsBoolean()  );
+    return IsChar() || IsInteger() || IsFloat() || IsConstant() || IsByte() || IsShort() ||
+        IsBoolean();
   }
   bool IsCategory2Types() const {
     return IsLowHalf();  // Don't expect explicit testing of high halves
@@ -230,20 +164,12 @@
     return IsChar() || IsBooleanTypes() || IsConstantChar();
   }
   bool IsIntegralTypes() const {
-    return (IsInteger() || IsConstant() || IsByte() || IsShort() || IsChar() || IsBoolean() );
+    return IsInteger() || IsConstant() || IsByte() || IsShort() || IsChar() || IsBoolean();
   }
-  inline virtual int32_t ConstantValue() const {
-    DCHECK(IsConstant());
-    return -1;
-  }
-  inline virtual int32_t ConstantValueLo() const {
-    DCHECK(IsConstantLo());
-    return -1;
-  }
-  inline virtual int32_t ConstantValueHi() const {
-    DCHECK(IsConstantHi());
-    return -1;
-  }
+  // Give the constant value encoded, but this shouldn't be called in the general case.
+  virtual int32_t ConstantValue() const;
+  virtual int32_t ConstantValueLo() const;
+  virtual int32_t ConstantValueHi() const;
   bool IsArrayIndexTypes() const {
     return IsIntegralTypes();
   }
@@ -265,12 +191,11 @@
   bool IsDoubleHighTypes() const {
     return (IsDoubleHi() || IsPreciseConstantHi() || IsImpreciseConstantHi());
   }
-  inline virtual bool IsLong() const {
+  virtual bool IsLong() const {
     return false;
   }
-  bool HasClass() const {
-    return IsReference() || IsPreciseReference() || IsUninitializedReference() ||
-           IsUninitializedThisReference();
+  virtual bool HasClass() const {
+    return false;
   }
   bool IsJavaLangObject() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool IsArrayTypes() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -279,210 +204,286 @@
   bool IsJavaLangObjectArray() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool IsInstantiableTypes() const;
   const std::string& GetDescriptor() const {
-    DCHECK(IsUnresolvedTypes() && !IsUnresolvedMergedReference() && !IsUnresolvedSuperClass());
+    DCHECK(HasClass() || (IsUnresolvedTypes() && !IsUnresolvedMergedReference() &&
+                          !IsUnresolvedSuperClass()));
     return descriptor_;
   }
-  uint16_t GetId() const {
-    return cache_id_;
-  }
-  const RegType& GetSuperClass(RegTypeCache* cache) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
-  // Can this type access other?
-  bool CanAccess(const RegType& other) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  // Can this type access a member with the given properties?
-  bool CanAccessMember(mirror::Class* klass, uint32_t access_flags) const
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  // Can this type be assigned by src?
-  bool IsAssignableFrom(const RegType& src) const  SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool Equals(const RegType& other) const {
-    return GetId() == other.GetId();
-  }
-  // Compute the merge of this register from one edge (path) with incoming_type from another.
-  virtual const RegType& Merge(const RegType& incoming_type, RegTypeCache* reg_types) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   mirror::Class* GetClass() const {
     DCHECK(!IsUnresolvedReference());
     DCHECK(klass_ != NULL);
     DCHECK(HasClass());
     return klass_;
   }
-    /*
-     * A basic Join operation on classes. For a pair of types S and T the Join, written S v T = J, is
-     * S <: J, T <: J and for-all U such that S <: U, T <: U then J <: U. That is J is the parent of
-     * S and T such that there isn't a parent of both S and T that isn't also the parent of J (ie J
-     * is the deepest (lowest upper bound) parent of S and T).
-     *
-     * This operation applies for regular classes and arrays, however, for interface types there needn't
-     * be a partial ordering on the types. We could solve the problem of a lack of a partial order by
-     * introducing sets of types, however, the only operation permissible on an interface is
-     * invoke-interface. In the tradition of Java verifiers [1] we defer the verification of interface
-     * types until an invoke-interface call on the interface typed reference at runtime and allow
-     * the perversion of Object being assignable to an interface type (note, however, that we don't
-     * allow assignment of Object or Interface to any concrete class and are therefore type safe).
-     *
-     * [1] Java bytecode verification: algorithms and formalizations, Xavier Leroy
-     */
+  uint16_t GetId() const {
+    return cache_id_;
+  }
+  const RegType& GetSuperClass(RegTypeCache* cache) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
+
+  // Can this type access other?
+  bool CanAccess(const RegType& other) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Can this type access a member with the given properties?
+  bool CanAccessMember(mirror::Class* klass, uint32_t access_flags) const
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Can this type be assigned by src?
+  // Note: Object and interface types may always be assigned to one another, see comment on
+  // ClassJoin.
+  bool IsAssignableFrom(const RegType& src) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Can this type be assigned by src? Variant of IsAssignableFrom that doesn't allow assignment to
+  // an interface from an Object.
+  bool IsStrictlyAssignableFrom(const RegType& src) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Are these RegTypes the same?
+  bool Equals(const RegType& other) const {
+    return GetId() == other.GetId();
+  }
+
+  // Compute the merge of this register from one edge (path) with incoming_type from another.
+  virtual const RegType& Merge(const RegType& incoming_type, RegTypeCache* reg_types) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  /*
+   * A basic Join operation on classes. For a pair of types S and T the Join, written S v T = J, is
+   * S <: J, T <: J and for-all U such that S <: U, T <: U then J <: U. That is J is the parent of
+   * S and T such that there isn't a parent of both S and T that isn't also the parent of J (ie J
+   * is the deepest (lowest upper bound) parent of S and T).
+   *
+   * This operation applies for regular classes and arrays, however, for interface types there
+   * needn't be a partial ordering on the types. We could solve the problem of a lack of a partial
+   * order by introducing sets of types, however, the only operation permissible on an interface is
+   * invoke-interface. In the tradition of Java verifiers [1] we defer the verification of interface
+   * types until an invoke-interface call on the interface typed reference at runtime and allow
+   * the perversion of Object being assignable to an interface type (note, however, that we don't
+   * allow assignment of Object or Interface to any concrete class and are therefore type safe).
+   *
+   * [1] Java bytecode verification: algorithms and formalizations, Xavier Leroy
+   */
   static mirror::Class* ClassJoin(mirror::Class* s, mirror::Class* t)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  RegType(mirror::Class* klass, std::string descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : descriptor_(descriptor), klass_(klass), cache_id_(cache_id) {
-  }
-  inline virtual ~RegType() {
-  }
-  virtual void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  friend class RegTypeCache;
+
+  virtual ~RegType() {}
 
  protected:
+  RegType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : descriptor_(descriptor), klass_(klass), cache_id_(cache_id) {
+    if (kIsDebugBuild) {
+      CheckInvariants();
+    }
+  }
+
+  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+
   const std::string descriptor_;
-  mirror::Class* klass_;
+  mirror::Class* const klass_;
   const uint16_t cache_id_;
 
+  friend class RegTypeCache;
+
   DISALLOW_COPY_AND_ASSIGN(RegType);
 };
 
+// Bottom type.
 class ConflictType : public RegType {
  public:
   bool IsConflict() const {
     return true;
   }
+
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static ConflictType* CreateInstance(mirror::Class* klass, std::string& descriptor,
-                                      uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Get the singleton Conflict instance.
   static ConflictType* GetInstance();
+
+  // Create the singleton instance.
+  static ConflictType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
+                                      uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Destroy the singleton instance.
   static void Destroy();
  private:
-  ConflictType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ConflictType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : RegType(klass, descriptor, cache_id) {
+  }
+
   static ConflictType* instance_;
 };
 
+// A variant of the bottom type used to specify an undefined value in the incoming registers.
+// Merging with UndefinedType yields ConflictType which is the true bottom.
 class UndefinedType : public RegType {
  public:
   bool IsUndefined() const {
     return true;
   }
+
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static UndefinedType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+
+  // Get the singleton Undefined instance.
+  static UndefinedType* GetInstance();
+
+  // Create the singleton instance.
+  static UndefinedType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                        uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static UndefinedType* GetInstance();
+
+  // Destroy the singleton instance.
   static void Destroy();
  private:
-  UndefinedType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+  UndefinedType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       : RegType(klass, descriptor, cache_id) {
   }
+
   virtual const RegType& Merge(const RegType& incoming_type, RegTypeCache* reg_types) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   static UndefinedType* instance_;
 };
 
-class IntegerType : public RegType {
+class PrimitiveType : public RegType {
+ public:
+  PrimitiveType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+};
+
+class Cat1Type : public PrimitiveType {
+ public:
+  Cat1Type(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+};
+
+class IntegerType : public Cat1Type {
  public:
   bool IsInteger() const {
     return true;
   }
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static IntegerType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+  static IntegerType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                      uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static IntegerType* GetInstance();
   static void Destroy();
  private:
-  IntegerType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  IntegerType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Cat1Type(klass, descriptor, cache_id) {
+  }
   static IntegerType* instance_;
 };
 
-class BooleanType : public RegType {
+class BooleanType : public Cat1Type {
  public:
   bool IsBoolean() const {
     return true;
   }
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static BooleanType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+  static BooleanType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                      uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static BooleanType* GetInstance();
   static void Destroy();
  private:
-  BooleanType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  BooleanType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Cat1Type(klass, descriptor, cache_id) {
+  }
+
   static BooleanType* instance;
 };
 
-class ByteType : public RegType {
+class ByteType : public Cat1Type {
  public:
   bool IsByte() const {
     return true;
   }
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static ByteType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+  static ByteType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                   uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static ByteType* GetInstance();
   static void Destroy();
  private:
-  ByteType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ByteType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Cat1Type(klass, descriptor, cache_id) {
+  }
   static ByteType* instance_;
 };
 
-class ShortType : public RegType {
+class ShortType : public Cat1Type {
  public:
   bool IsShort() const {
     return true;
   }
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static ShortType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+  static ShortType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                    uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static ShortType* GetInstance();
   static void Destroy();
  private:
-  ShortType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ShortType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Cat1Type(klass, descriptor, cache_id) {
+  }
   static ShortType* instance_;
 };
 
-class CharType : public RegType {
+class CharType : public Cat1Type {
  public:
   bool IsChar() const {
     return true;
   }
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static CharType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+  static CharType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                   uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static CharType* GetInstance();
   static void Destroy();
  private:
-  CharType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  CharType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Cat1Type(klass, descriptor, cache_id) {
+  }
   static CharType* instance_;
 };
 
-class FloatType : public RegType {
+class FloatType : public Cat1Type {
  public:
   bool IsFloat() const {
     return true;
   }
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static FloatType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+  static FloatType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                    uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static FloatType* GetInstance();
   static void Destroy();
  private:
-  FloatType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  FloatType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Cat1Type(klass, descriptor, cache_id) {
+  }
   static FloatType* instance_;
 };
 
-class LongLoType : public RegType {
+class Cat2Type : public PrimitiveType {
+ public:
+  Cat2Type(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+};
+
+class LongLoType : public Cat2Type {
  public:
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool IsLongLo() const {
@@ -491,35 +492,39 @@
   bool IsLong() const {
     return true;
   }
-  static LongLoType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+  static LongLoType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                     uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
    static LongLoType* GetInstance();
   static void Destroy();
  private:
-  LongLoType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  LongLoType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Cat2Type(klass, descriptor, cache_id) {
+  }
   static LongLoType* instance_;
 };
 
-class LongHiType : public RegType {
+class LongHiType : public Cat2Type {
  public:
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool IsLongHi() const {
     return true;
   }
-  static LongHiType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+  static LongHiType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                     uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static LongHiType* GetInstance();
   static void Destroy();
  private:
-  LongHiType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  LongHiType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Cat2Type(klass, descriptor, cache_id) {
+  }
   static LongHiType* instance_;
 };
 
-class DoubleLoType : public RegType {
+class DoubleLoType : public Cat2Type {
  public:
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool IsDoubleLo() const {
@@ -528,31 +533,35 @@
   bool IsDouble() const {
     return true;
   }
-  static DoubleLoType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+  static DoubleLoType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                       uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static DoubleLoType* GetInstance();
   static void Destroy();
  private:
-  DoubleLoType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  DoubleLoType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Cat2Type(klass, descriptor, cache_id) {
+  }
   static DoubleLoType* instance_;
 };
 
-class DoubleHiType : public RegType {
+class DoubleHiType : public Cat2Type {
  public:
   std::string Dump() const;
   virtual bool IsDoubleHi() const {
     return true;
   }
-  static DoubleHiType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+  static DoubleHiType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                       uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static DoubleHiType* GetInstance();
   static void Destroy();
  private:
-  DoubleHiType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  DoubleHiType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Cat2Type(klass, descriptor, cache_id) {
+  }
   static DoubleHiType* instance_;
 };
 
@@ -560,9 +569,6 @@
  public:
   ConstantType(uint32_t constat, uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  inline virtual ~ConstantType() {
-  }
-  const uint32_t constant_;
   // If this is a 32-bit constant, what is the value? This value may be imprecise in which case
   // the value represents part of the integer range of values that may be held in the register.
   virtual int32_t ConstantValue() const;
@@ -590,7 +596,10 @@
            ConstantValue() >= std::numeric_limits<jshort>::min() &&
            ConstantValue() <= std::numeric_limits<jshort>::max();
   }
-  inline virtual bool IsConstantTypes() const { return true; }
+  virtual bool IsConstantTypes() const { return true; }
+
+ private:
+  const uint32_t constant_;
 };
 
 class PreciseConstType : public ConstantType {
@@ -662,147 +671,254 @@
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 };
 
+// Common parent of all uninitialized types. Uninitialized types are created by "new" dex
+// instructions and must be passed to a constructor.
 class UninitializedType : public RegType {
  public:
-  UninitializedType(mirror::Class* klass, std::string& descriptor, uint32_t allocation_pc,
-                    uint16_t cache_id);
-  inline virtual ~UninitializedType() {
+  UninitializedType(mirror::Class* klass, const std::string& descriptor, uint32_t allocation_pc,
+                    uint16_t cache_id)
+      : RegType(klass, descriptor, cache_id), allocation_pc_(allocation_pc) {
   }
 
+  bool IsUninitializedTypes() const;
+  bool IsNonZeroReferenceTypes() const;
+
   uint32_t GetAllocationPc() const {
     DCHECK(IsUninitializedTypes());
     return allocation_pc_;
   }
-  virtual void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  private:
   const uint32_t allocation_pc_;
 };
 
-class UninitialisedReferenceType : public UninitializedType {
+// Similar to ReferenceType but not yet having been passed to a constructor.
+class UninitializedReferenceType : public UninitializedType {
  public:
-  UninitialisedReferenceType(mirror::Class* klass, std::string& descriptor, uint32_t allocation_pc,
-                             uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  UninitializedReferenceType(mirror::Class* klass, const std::string& descriptor,
+                             uint32_t allocation_pc, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : UninitializedType(klass, descriptor, allocation_pc, cache_id) {
+  }
 
   bool IsUninitializedReference() const {
     return true;
   }
+
+  bool HasClass() const {
+    return true;
+  }
+
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 };
 
+// Similar to UnresolvedReferenceType but not yet having been passed to a constructor.
 class UnresolvedUninitializedRefType : public UninitializedType {
  public:
-  UnresolvedUninitializedRefType(std::string& descriptor, uint32_t allocation_pc,
-                                 uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  UnresolvedUninitializedRefType(const std::string& descriptor, uint32_t allocation_pc,
+                                 uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : UninitializedType(NULL, descriptor, allocation_pc, cache_id) {
+    if (kIsDebugBuild) {
+      CheckInvariants();
+    }
+  }
+
   bool IsUnresolvedAndUninitializedReference() const {
     return true;
   }
+
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ private:
+  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 };
 
-class UninitialisedThisReferenceType : public UninitializedType {
+// Similar to UninitializedReferenceType but special case for the this argument of a constructor.
+class UninitializedThisReferenceType : public UninitializedType {
  public:
-  UninitialisedThisReferenceType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  inline virtual bool IsUninitializedThisReference() const {
+  UninitializedThisReferenceType(mirror::Class* klass, const std::string& descriptor,
+                                 uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : UninitializedType(klass, descriptor, 0, cache_id) {
+    if (kIsDebugBuild) {
+      CheckInvariants();
+    }
+  }
+
+  virtual bool IsUninitializedThisReference() const {
     return true;
   }
+
+  bool HasClass() const {
+    return true;
+  }
+
+  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ private:
+  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 };
 
-class UnresolvedUninitialisedThisRefType : public UninitializedType {
+class UnresolvedUninitializedThisRefType : public UninitializedType {
  public:
-  UnresolvedUninitialisedThisRefType(std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  UnresolvedUninitializedThisRefType(const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : UninitializedType(NULL, descriptor, 0, cache_id) {
+    if (kIsDebugBuild) {
+      CheckInvariants();
+    }
+  }
+
   bool IsUnresolvedAndUninitializedThisReference() const {
     return true;
   }
+
+  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ private:
+  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 };
 
+// A type of register holding a reference to an Object of type GetClass or a sub-class.
 class ReferenceType : public RegType {
  public:
-  ReferenceType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ReferenceType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+     : RegType(klass, descriptor, cache_id) {
+  }
+
   bool IsReference() const {
     return true;
   }
+
+  bool IsNonZeroReferenceTypes() const {
+    return true;
+  }
+
+  bool HasClass() const {
+    return true;
+  }
+
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 };
 
+// A type of register holding a reference to an Object of type GetClass and only an object of that
+// type.
 class PreciseReferenceType : public RegType {
  public:
-  PreciseReferenceType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+  PreciseReferenceType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   bool IsPreciseReference() const {
     return true;
   }
+
+  bool IsNonZeroReferenceTypes() const {
+    return true;
+  }
+
+  bool HasClass() const {
+    return true;
+  }
+
+  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 };
 
-class UnresolvedReferenceType : public RegType {
+// Common parent of unresolved types.
+class UnresolvedType : public RegType {
  public:
-  UnresolvedReferenceType(std::string& descriptor, uint16_t cache_id)
-     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : RegType(NULL, descriptor, cache_id) {
+  UnresolvedType(const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : RegType(NULL, descriptor, cache_id) {
   }
-  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  bool IsNonZeroReferenceTypes() const;
+};
+
+// Similar to ReferenceType except the Class couldn't be loaded. Assignability and other tests made
+// of this type must be conservative.
+class UnresolvedReferenceType : public UnresolvedType {
+ public:
+  UnresolvedReferenceType(const std::string& descriptor, uint16_t cache_id)
+     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : UnresolvedType(descriptor, cache_id) {
+    if (kIsDebugBuild) {
+      CheckInvariants();
+    }
+  }
+
   bool IsUnresolvedReference() const {
     return true;
   }
+
+  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ private:
+  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 };
 
-class UnresolvedSuperClass : public RegType {
+// Type representing the super-class of an unresolved type.
+class UnresolvedSuperClass : public UnresolvedType {
  public:
   UnresolvedSuperClass(uint16_t child_id, RegTypeCache* reg_type_cache, uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : RegType(NULL, "", cache_id), unresolved_child_id_(child_id),
+      : UnresolvedType("", cache_id), unresolved_child_id_(child_id),
         reg_type_cache_(reg_type_cache) {
+    if (kIsDebugBuild) {
+      CheckInvariants();
+    }
   }
+
   bool IsUnresolvedSuperClass() const {
     return true;
   }
+
   uint16_t GetUnresolvedSuperClassChildId() const {
     DCHECK(IsUnresolvedSuperClass());
     return static_cast<uint16_t>(unresolved_child_id_ & 0xFFFF);
   }
-  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
  private:
+  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const uint16_t unresolved_child_id_;
   const RegTypeCache* const reg_type_cache_;
 };
 
-class UnresolvedMergedType : public RegType {
+// A merge of two unresolved types. If the types were resolved this may be Conflict or another
+// known ReferenceType.
+class UnresolvedMergedType : public UnresolvedType {
  public:
-  UnresolvedMergedType(uint16_t left_id, uint16_t right_id, const RegTypeCache* reg_type_cache, uint16_t cache_id)
+  UnresolvedMergedType(uint16_t left_id, uint16_t right_id, const RegTypeCache* reg_type_cache,
+                       uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : RegType(NULL, "", cache_id), reg_type_cache_(reg_type_cache) ,merged_types_(left_id, right_id) {
+      : UnresolvedType("", cache_id), reg_type_cache_(reg_type_cache) ,merged_types_(left_id, right_id) {
+    if (kIsDebugBuild) {
+      CheckInvariants();
+    }
   }
+
   // The top of a tree of merged types.
   std::pair<uint16_t, uint16_t> GetTopMergedTypes() const {
     DCHECK(IsUnresolvedMergedReference());
     return merged_types_;
   }
+
   // The complete set of merged types.
   std::set<uint16_t> GetMergedTypes() const;
+
   bool IsUnresolvedMergedReference() const {
     return true;
   }
-  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
  private:
+  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const RegTypeCache* const reg_type_cache_;
   const std::pair<uint16_t, uint16_t> merged_types_;
 };
 
 std::ostream& operator<<(std::ostream& os, const RegType& rhs)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
 }  // namespace verifier
 }  // namespace art
 
diff --git a/src/verifier/reg_type_cache-inl.h b/src/verifier/reg_type_cache-inl.h
index f6b0056..42474d1 100644
--- a/src/verifier/reg_type_cache-inl.h
+++ b/src/verifier/reg_type_cache-inl.h
@@ -24,7 +24,7 @@
 namespace art {
 namespace verifier {
 template <class Type>
-Type* RegTypeCache::CreatePrimitiveTypeInstance(std::string descriptor) {
+Type* RegTypeCache::CreatePrimitiveTypeInstance(const std::string& descriptor) {
   mirror::Class* klass = NULL;
   // Try loading the class from linker.
   if (!descriptor.empty()) {
@@ -35,6 +35,12 @@
   return entry;
 }
 
+inline const art::verifier::RegType& RegTypeCache::GetFromId(uint16_t id) const {
+  DCHECK_LT(id, entries_.size());
+  RegType* result = entries_[id];
+  DCHECK(result != NULL);
+  return *result;
+}
 }  // namespace verifier
 }  // namespace art
 #endif  // ART_SRC_VERIFIER_REG_TYPE_CACHE_INL_H_
diff --git a/src/verifier/reg_type_cache.cc b/src/verifier/reg_type_cache.cc
index e914d1e..6013250 100644
--- a/src/verifier/reg_type_cache.cc
+++ b/src/verifier/reg_type_cache.cc
@@ -24,13 +24,24 @@
 
 namespace art {
 namespace verifier {
+
 bool RegTypeCache::primitive_initialized_ = false;
 uint16_t RegTypeCache::primitive_start_ = 0;
 uint16_t RegTypeCache::primitive_count_ = 0;
 
 static bool MatchingPrecisionForClass(RegType* entry, bool precise)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return (entry->IsPreciseReference() == precise) || (entry->GetClass()->IsFinal() && !precise);
+  if (entry->IsPreciseReference() == precise) {
+    // We were or weren't looking for a precise reference and we found what we need.
+    return true;
+  } else {
+    if (!precise && entry->GetClass()->CannotBeAssignedFromOtherTypes()) {
+      // We weren't looking for a precise reference, as we're looking up based on a descriptor, but
+      // we found a matching entry based on the descriptor. Return the precise entry in that case.
+      return true;
+    }
+    return false;
+  }
 }
 
 void RegTypeCache::FillPrimitiveTypes() {
@@ -49,9 +60,10 @@
   DCHECK_EQ(entries_.size(), primitive_count_);
 }
 
-const RegType& RegTypeCache::FromDescriptor(mirror::ClassLoader* loader, const char* descriptor, bool precise) {
-  CHECK(RegTypeCache::primitive_initialized_);
-  if (std::string(descriptor).length() == 1) {
+const RegType& RegTypeCache::FromDescriptor(mirror::ClassLoader* loader, const char* descriptor,
+                                            bool precise) {
+  DCHECK(RegTypeCache::primitive_initialized_);
+  if (descriptor[1] == '\0') {
     switch (descriptor[0]) {
       case 'Z':
         return Boolean();
@@ -80,15 +92,7 @@
   }
 };
 
-const art::verifier::RegType& RegTypeCache::GetFromId(uint16_t id) const {
-  DCHECK_LT(id, entries_.size());
-  RegType* result = entries_[id];
-  DCHECK(result != NULL);
-  return *result;
-}
-
-const RegType& RegTypeCache::RegTypeFromPrimitiveType(
-    Primitive::Type prim_type) const {
+const RegType& RegTypeCache::RegTypeFromPrimitiveType(Primitive::Type prim_type) const {
   CHECK(RegTypeCache::primitive_initialized_);
   switch (prim_type) {
     case Primitive::kPrimBoolean:
@@ -113,41 +117,29 @@
   }
 }
 
-bool RegTypeCache::MatchDescriptor(size_t idx, std::string& descriptor, bool precise) {
-  RegType* cur_entry = entries_[idx];
-  if (cur_entry->HasClass()) {
-    // Check the descriptor in the reg_type if available.
-    if(!cur_entry->descriptor_.empty()) {
-      if (descriptor == cur_entry->descriptor_ && MatchingPrecisionForClass(cur_entry, precise)) {
-        return true;
-      }
-    } else {
-      // Descriptor not found in reg_type , maybe available in Class object.
-      // So we might have cases where we have the class but not the descriptor
-      // for that class we need the class helper to get the descriptor
-      // and match it with the one we are given.
-      ClassHelper kh(cur_entry->GetClass());
-      if ((strcmp(descriptor.c_str(), kh.GetDescriptor()) == 0) &&
-          MatchingPrecisionForClass(cur_entry, precise)) {
-        return true;
-      }
-    }
-  } else if (cur_entry->IsUnresolvedReference() && cur_entry->GetDescriptor() == descriptor) {
-    return true;
+bool RegTypeCache::MatchDescriptor(size_t idx, const char* descriptor, bool precise) {
+  RegType* entry = entries_[idx];
+  if (entry->descriptor_ != descriptor) {
+    return false;
   }
-  return false;
+  if (entry->HasClass()) {
+    return MatchingPrecisionForClass(entry, precise);
+  }
+  // There is no notion of precise unresolved references, the precise information is just dropped
+  // on the floor.
+  DCHECK(entry->IsUnresolvedReference());
+  return true;
 }
 
-
-mirror::Class* RegTypeCache::ResolveClass(std::string descriptor, mirror::ClassLoader* loader) {
+mirror::Class* RegTypeCache::ResolveClass(const char* descriptor, mirror::ClassLoader* loader) {
   // Class was not found, must create new type.
   // Try resolving class
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   mirror::Class* klass = NULL;
   if (can_load_classes_) {
-    klass = class_linker->FindClass(descriptor.c_str(), loader);
+    klass = class_linker->FindClass(descriptor, loader);
   } else {
-    klass = class_linker->LookupClass(descriptor.c_str(), loader);
+    klass = class_linker->LookupClass(descriptor, loader);
     if (klass != NULL && !klass->IsLoaded()) {
       // We found the class but without it being loaded its not safe for use.
       klass = NULL;
@@ -155,6 +147,7 @@
   }
   return klass;
 }
+
 void RegTypeCache::ClearException() {
   if (can_load_classes_) {
     DCHECK(Thread::Current()->IsExceptionPending());
@@ -163,8 +156,9 @@
     DCHECK(!Thread::Current()->IsExceptionPending());
   }
 }
-const RegType& RegTypeCache::From(mirror::ClassLoader* loader, std::string descriptor, bool precise) {
 
+const RegType& RegTypeCache::From(mirror::ClassLoader* loader, const char* descriptor,
+                                  bool precise) {
   // Try looking up the class in the cache first.
   for (size_t i = primitive_count_; i < entries_.size(); i++) {
     if (MatchDescriptor(i, descriptor, precise)) {
@@ -185,7 +179,7 @@
     // 2- Precise Flag passed as true.
     RegType* entry;
     // Create an imprecise type if we can't tell for a fact that it is precise.
-    if ((klass->IsFinal()) || precise) {
+    if (klass->CannotBeAssignedFromOtherTypes() || precise) {
       DCHECK(!(klass->IsAbstract()) || klass->IsArrayClass());
       DCHECK(!klass->IsInterface());
       entry = new PreciseReferenceType(klass, descriptor, entries_.size());
@@ -198,7 +192,7 @@
     // We tried loading the class and failed, this might get an exception raised
     // so we want to clear it before we go on.
     ClearException();
-    if (IsValidDescriptor(descriptor.c_str())) {
+    if (IsValidDescriptor(descriptor)) {
       RegType* entry = new UnresolvedReferenceType(descriptor, entries_.size());
       entries_.push_back(entry);
       return *entry;
@@ -209,25 +203,26 @@
     }
   }
 }
-const RegType& RegTypeCache::FromClass(mirror::Class* klass, bool precise) {
+
+const RegType& RegTypeCache::FromClass(const char* descriptor, mirror::Class* klass, bool precise) {
   if (klass->IsPrimitive()) {
+    // Note: precise isn't used for primitive classes. A char is assignable to an int. All
+    // primitive classes are final.
     return RegTypeFromPrimitiveType(klass->GetPrimitiveType());
   } else {
     // Look for the reference in the list of entries to have.
     for (size_t i = primitive_count_; i < entries_.size(); i++) {
       RegType* cur_entry = entries_[i];
-      if ((cur_entry->HasClass()) && cur_entry->GetClass() == klass &&
-          MatchingPrecisionForClass(cur_entry, precise)) {
+      if (cur_entry->klass_ == klass && MatchingPrecisionForClass(cur_entry, precise)) {
         return *cur_entry;
       }
     }
     // No reference to the class was found, create new reference.
     RegType* entry;
-    std::string empty = "";
     if (precise) {
-      entry = new PreciseReferenceType(klass, empty, entries_.size());
+      entry = new PreciseReferenceType(klass, descriptor, entries_.size());
     } else {
-      entry = new ReferenceType(klass, empty, entries_.size());
+      entry = new ReferenceType(klass, descriptor, entries_.size());
     }
     entries_.push_back(entry);
     return *entry;
@@ -309,13 +304,14 @@
   // Create entry.
   RegType* entry = new UnresolvedMergedType(left.GetId(), right.GetId(), this, entries_.size());
   entries_.push_back(entry);
-#ifndef NDEBUG
-  UnresolvedMergedType* tmp_entry = down_cast<UnresolvedMergedType*>(entry);
-  std::set<uint16_t> check_types = tmp_entry->GetMergedTypes();
-  CHECK(check_types == types);
-#endif
+  if (kIsDebugBuild) {
+    UnresolvedMergedType* tmp_entry = down_cast<UnresolvedMergedType*>(entry);
+    std::set<uint16_t> check_types = tmp_entry->GetMergedTypes();
+    CHECK(check_types == types);
+  }
   return *entry;
 }
+
 const RegType& RegTypeCache::FromUnresolvedSuperClass(const RegType& child) {
   // Check if entry already exists.
   for (size_t i = primitive_count_; i < entries_.size(); i++) {
@@ -334,11 +330,12 @@
   entries_.push_back(entry);
   return *entry;
 }
+
 const RegType& RegTypeCache::Uninitialized(const RegType& type, uint32_t allocation_pc) {
   RegType* entry = NULL;
   RegType* cur_entry = NULL;
+  const std::string& descriptor(type.GetDescriptor());
   if (type.IsUnresolvedTypes()) {
-    std::string descriptor(type.GetDescriptor());
     for (size_t i = primitive_count_; i < entries_.size(); i++) {
       cur_entry = entries_[i];
       if (cur_entry->IsUnresolvedAndUninitializedReference() &&
@@ -353,23 +350,23 @@
     for (size_t i = primitive_count_; i < entries_.size(); i++) {
       cur_entry = entries_[i];
       if (cur_entry->IsUninitializedReference() &&
-          down_cast<UninitialisedReferenceType*>(cur_entry)
+          down_cast<UninitializedReferenceType*>(cur_entry)
               ->GetAllocationPc() == allocation_pc &&
           cur_entry->GetClass() == klass) {
         return *cur_entry;
       }
     }
-    std::string descriptor("");
-    entry = new UninitialisedReferenceType(klass, descriptor, allocation_pc, entries_.size());
+    entry = new UninitializedReferenceType(klass, descriptor, allocation_pc, entries_.size());
   }
   entries_.push_back(entry);
   return *entry;
 }
+
 const RegType& RegTypeCache::FromUninitialized(const RegType& uninit_type) {
   RegType* entry;
 
   if (uninit_type.IsUnresolvedTypes()) {
-    std::string descriptor(uninit_type.GetDescriptor());
+    const std::string& descriptor(uninit_type.GetDescriptor());
     for (size_t i = primitive_count_; i < entries_.size(); i++) {
       RegType* cur_entry = entries_[i];
       if (cur_entry->IsUnresolvedReference() &&
@@ -377,63 +374,52 @@
         return *cur_entry;
       }
     }
-    entry = new UnresolvedReferenceType(descriptor, entries_.size());
+    entry = new UnresolvedReferenceType(descriptor.c_str(), entries_.size());
   } else {
     mirror::Class* klass = uninit_type.GetClass();
     if(uninit_type.IsUninitializedThisReference() && !klass->IsFinal()) {
-      // For uninitialized this reference look for reference types that are not precise.
+      // For uninitialized "this reference" look for reference types that are not precise.
       for (size_t i = primitive_count_; i < entries_.size(); i++) {
         RegType* cur_entry = entries_[i];
         if (cur_entry->IsReference() && cur_entry->GetClass() == klass) {
           return *cur_entry;
         }
       }
-      std::string descriptor("");
-      entry = new ReferenceType(klass, descriptor, entries_.size());
-    } else {
-        std::string descriptor;
-        if (klass->IsFinal()) {
-          if (klass->IsInstantiable()) {
-            for (size_t i = primitive_count_; i < entries_.size(); i++) {
-              RegType* cur_entry = entries_[i];
-              if (cur_entry->IsPreciseReference() && cur_entry->GetClass() == klass) {
-                return *cur_entry;
-              }
-            }
-            // Precise type was not found , create one !
-            entry = new PreciseReferenceType(klass, descriptor, entries_.size());
-          } else {
-            return Conflict();
-          }
-      } else {
-        // Not a final class, create an imprecise reference. Look up if we have it in the cache first.
-        for (size_t i = primitive_count_; i < entries_.size(); i++) {
-          RegType* cur_entry = entries_[i];
-          if (cur_entry->IsReference() && !(cur_entry->IsPrecise()) &&
-              cur_entry->GetClass() == klass) {
-            return *cur_entry;
-          }
+      entry = new ReferenceType(klass, "", entries_.size());
+    } else if (klass->IsInstantiable()) {
+      // We're uninitialized because of allocation, look or create a precise type as allocations
+      // may only create objects of that type.
+      for (size_t i = primitive_count_; i < entries_.size(); i++) {
+        RegType* cur_entry = entries_[i];
+        if (cur_entry->IsPreciseReference() && cur_entry->GetClass() == klass) {
+          return *cur_entry;
         }
-        entry = new ReferenceType(klass, descriptor, entries_.size());
       }
+      entry = new PreciseReferenceType(klass, uninit_type.GetDescriptor(), entries_.size());
+    } else {
+      return Conflict();
     }
  }
   entries_.push_back(entry);
   return *entry;
 }
-const RegType& RegTypeCache::ByteConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+
+const RegType& RegTypeCache::ByteConstant() {
   return FromCat1Const(std::numeric_limits<jbyte>::min(), false);
 }
-const RegType& RegTypeCache::ShortConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+
+const RegType& RegTypeCache::ShortConstant() {
   return FromCat1Const(std::numeric_limits<jshort>::min(), false);
 }
-const RegType& RegTypeCache::IntConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+
+const RegType& RegTypeCache::IntConstant() {
   return FromCat1Const(std::numeric_limits<jint>::max(), false);
 }
+
 const RegType& RegTypeCache::UninitializedThisArgument(const RegType& type) {
   RegType* entry;
+  const std::string& descriptor(type.GetDescriptor());
   if (type.IsUnresolvedTypes()) {
-    std::string descriptor(type.GetDescriptor());
     for (size_t i = primitive_count_; i < entries_.size(); i++) {
       RegType* cur_entry = entries_[i];
       if (cur_entry->IsUnresolvedAndUninitializedThisReference() &&
@@ -441,26 +427,26 @@
         return *cur_entry;
       }
     }
-    entry = new UnresolvedUninitialisedThisRefType(descriptor, entries_.size());
+    entry = new UnresolvedUninitializedThisRefType(descriptor, entries_.size());
   } else {
     mirror::Class* klass = type.GetClass();
     for (size_t i = primitive_count_; i < entries_.size(); i++) {
       RegType* cur_entry = entries_[i];
-      if (cur_entry->IsUninitializedThisReference() &&
-          cur_entry->GetClass() == klass) {
+      if (cur_entry->IsUninitializedThisReference() && cur_entry->GetClass() == klass) {
         return *cur_entry;
       }
     }
-    std::string descriptor("");
-    entry = new UninitialisedThisReferenceType(klass, descriptor, entries_.size());
+    entry = new UninitializedThisReferenceType(klass, descriptor, entries_.size());
   }
   entries_.push_back(entry);
   return *entry;
 }
+
 const RegType& RegTypeCache::FromCat1Const(int32_t value, bool precise) {
   for (size_t i = primitive_count_; i < entries_.size(); i++) {
     RegType* cur_entry = entries_[i];
-    if (cur_entry->IsConstant() && cur_entry->IsPreciseConstant() == precise &&
+    if (cur_entry->klass_ == NULL && cur_entry->IsConstant() &&
+        cur_entry->IsPreciseConstant() == precise &&
         (down_cast<ConstantType*>(cur_entry))->ConstantValue() == value) {
       return *cur_entry;
     }
@@ -514,12 +500,13 @@
 const RegType& RegTypeCache::GetComponentType(const RegType& array, mirror::ClassLoader* loader) {
   CHECK(array.IsArrayTypes());
   if (array.IsUnresolvedTypes()) {
-    std::string descriptor(array.GetDescriptor());
-    std::string component(descriptor.substr(1, descriptor.size() - 1));
+    const std::string& descriptor(array.GetDescriptor());
+    const std::string component(descriptor.substr(1, descriptor.size() - 1));
     return FromDescriptor(loader, component.c_str(), false);
   } else {
     mirror::Class* klass = array.GetClass()->GetComponentType();
-    return FromClass(klass, klass->IsFinal());
+    return FromClass(ClassHelper(klass).GetDescriptor(), klass,
+                     klass->CannotBeAssignedFromOtherTypes());
   }
 }
 
diff --git a/src/verifier/reg_type_cache.h b/src/verifier/reg_type_cache.h
index 602c950..d70123c 100644
--- a/src/verifier/reg_type_cache.h
+++ b/src/verifier/reg_type_cache.h
@@ -39,6 +39,7 @@
 class RegTypeCache {
  public:
   explicit RegTypeCache(bool can_load_classes) : can_load_classes_(can_load_classes) {
+    entries_.reserve(64);
     FillPrimitiveTypes();
   }
   ~RegTypeCache();
@@ -52,13 +53,13 @@
   }
   static void ShutDown();
   const art::verifier::RegType& GetFromId(uint16_t id) const;
-  const RegType& From(mirror::ClassLoader* loader, std::string descriptor, bool precise)
+  const RegType& From(mirror::ClassLoader* loader, const char* descriptor, bool precise)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   template <class Type>
-  static Type* CreatePrimitiveTypeInstance(std::string descriptor)
+  static Type* CreatePrimitiveTypeInstance(const std::string& descriptor)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void FillPrimitiveTypes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  const RegType& FromClass(mirror::Class* klass, bool precise)
+  const RegType& FromClass(const char* descriptor, mirror::Class* klass, bool precise)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const RegType& FromCat1Const(int32_t value, bool precise)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -152,10 +153,10 @@
   // Whether or not we're allowed to load classes.
   const bool can_load_classes_;
   DISALLOW_COPY_AND_ASSIGN(RegTypeCache);
-  mirror::Class* ResolveClass(std::string descriptor, mirror::ClassLoader* loader)
+  mirror::Class* ResolveClass(const char* descriptor, mirror::ClassLoader* loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void ClearException();
-  bool MatchDescriptor(size_t idx, std::string& descriptor, bool precise)
+  bool MatchDescriptor(size_t idx, const char* descriptor, bool precise)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 };
 
diff --git a/src/verifier/reg_type_test.cc b/src/verifier/reg_type_test.cc
index 9b46a7f..f37edff 100644
--- a/src/verifier/reg_type_test.cc
+++ b/src/verifier/reg_type_test.cc
@@ -74,7 +74,6 @@
 }
 
 TEST_F(RegTypeTest, Primitives) {
-
   ScopedObjectAccess soa(Thread::Current());
   RegTypeCache cache(true);
 
@@ -108,6 +107,7 @@
   EXPECT_FALSE(bool_reg_type.IsLongTypes());
   EXPECT_FALSE(bool_reg_type.IsDoubleTypes());
   EXPECT_TRUE(bool_reg_type.IsArrayIndexTypes());
+  EXPECT_FALSE(bool_reg_type.IsNonZeroReferenceTypes());
 
   const RegType& byte_reg_type = cache.Byte();
   EXPECT_FALSE(byte_reg_type.IsUndefined());
@@ -139,6 +139,7 @@
   EXPECT_FALSE(byte_reg_type.IsLongTypes());
   EXPECT_FALSE(byte_reg_type.IsDoubleTypes());
   EXPECT_TRUE(byte_reg_type.IsArrayIndexTypes());
+  EXPECT_FALSE(byte_reg_type.IsNonZeroReferenceTypes());
 
   const RegType& char_reg_type = cache.Char();
   EXPECT_FALSE(char_reg_type.IsUndefined());
@@ -170,6 +171,7 @@
   EXPECT_FALSE(char_reg_type.IsLongTypes());
   EXPECT_FALSE(char_reg_type.IsDoubleTypes());
   EXPECT_TRUE(char_reg_type.IsArrayIndexTypes());
+  EXPECT_FALSE(char_reg_type.IsNonZeroReferenceTypes());
 
   const RegType& short_reg_type = cache.Short();
   EXPECT_FALSE(short_reg_type.IsUndefined());
@@ -201,6 +203,7 @@
   EXPECT_FALSE(short_reg_type.IsLongTypes());
   EXPECT_FALSE(short_reg_type.IsDoubleTypes());
   EXPECT_TRUE(short_reg_type.IsArrayIndexTypes());
+  EXPECT_FALSE(short_reg_type.IsNonZeroReferenceTypes());
 
   const RegType& int_reg_type = cache.Integer();
   EXPECT_FALSE(int_reg_type.IsUndefined());
@@ -232,6 +235,7 @@
   EXPECT_FALSE(int_reg_type.IsLongTypes());
   EXPECT_FALSE(int_reg_type.IsDoubleTypes());
   EXPECT_TRUE(int_reg_type.IsArrayIndexTypes());
+  EXPECT_FALSE(int_reg_type.IsNonZeroReferenceTypes());
 
   const RegType& long_reg_type = cache.LongLo();
   EXPECT_FALSE(long_reg_type.IsUndefined());
@@ -263,6 +267,7 @@
   EXPECT_TRUE(long_reg_type.IsLongTypes());
   EXPECT_FALSE(long_reg_type.IsDoubleTypes());
   EXPECT_FALSE(long_reg_type.IsArrayIndexTypes());
+  EXPECT_FALSE(long_reg_type.IsNonZeroReferenceTypes());
 
   const RegType& float_reg_type = cache.Float();
   EXPECT_FALSE(float_reg_type.IsUndefined());
@@ -294,6 +299,7 @@
   EXPECT_FALSE(float_reg_type.IsLongTypes());
   EXPECT_FALSE(float_reg_type.IsDoubleTypes());
   EXPECT_FALSE(float_reg_type.IsArrayIndexTypes());
+  EXPECT_FALSE(float_reg_type.IsNonZeroReferenceTypes());
 
   const RegType& double_reg_type = cache.DoubleLo();
   EXPECT_FALSE(double_reg_type.IsUndefined());
@@ -325,6 +331,7 @@
   EXPECT_FALSE(double_reg_type.IsLongTypes());
   EXPECT_TRUE(double_reg_type.IsDoubleTypes());
   EXPECT_FALSE(double_reg_type.IsArrayIndexTypes());
+  EXPECT_FALSE(double_reg_type.IsNonZeroReferenceTypes());
 }
 
 
@@ -352,12 +359,14 @@
   RegTypeCache cache(true);
   const RegType& ref_type_0 = cache.FromDescriptor(NULL, "Ljava/lang/DoesNotExist;", true);
   EXPECT_TRUE(ref_type_0.IsUnresolvedReference());
+  EXPECT_TRUE(ref_type_0.IsNonZeroReferenceTypes());
 
   const RegType& ref_type_1 = cache.FromDescriptor(NULL, "Ljava/lang/DoesNotExist;", true);
   EXPECT_TRUE(ref_type_0.Equals(ref_type_1));
 
   const RegType& unresolved_super_class =  cache.FromUnresolvedSuperClass(ref_type_0);
   EXPECT_TRUE(unresolved_super_class.IsUnresolvedSuperClass());
+  EXPECT_TRUE(unresolved_super_class.IsNonZeroReferenceTypes());
 }
 
 TEST_F(RegTypeReferenceTest, UnresolvedUnintializedType) {
@@ -372,6 +381,7 @@
   const RegType& unresolved_unintialised = cache.Uninitialized(ref_type, 1101ull);
   EXPECT_TRUE(unresolved_unintialised.IsUnresolvedAndUninitializedReference());
   EXPECT_TRUE(unresolved_unintialised.IsUninitializedTypes());
+  EXPECT_TRUE(unresolved_unintialised.IsNonZeroReferenceTypes());
   // Create an uninitialized type of this unresolved type with different  PC
   const RegType& ref_type_unresolved_unintialised_1 =  cache.Uninitialized(ref_type, 1102ull);
   EXPECT_TRUE(unresolved_unintialised.IsUnresolvedAndUninitializedReference());
diff --git a/src/verifier/register_line-inl.h b/src/verifier/register_line-inl.h
new file mode 100644
index 0000000..157e136
--- /dev/null
+++ b/src/verifier/register_line-inl.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 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_VERIFIER_REGISTER_LINE_INL_H_
+#define ART_SRC_VERIFIER_REGISTER_LINE_INL_H_
+
+#include "register_line.h"
+#include "method_verifier.h"
+
+namespace art {
+namespace verifier {
+
+inline const RegType& RegisterLine::GetRegisterType(uint32_t vsrc) const {
+  // The register index was validated during the static pass, so we don't need to check it here.
+  DCHECK_LT(vsrc, num_regs_);
+  return verifier_->GetRegTypeCache()->GetFromId(line_[vsrc]);
+}
+
+}  // namespace verifier
+}  // namespace art
+
+#endif  // ART_SRC_VERIFIER_REGISTER_LINE_INL_H_
diff --git a/src/verifier/register_line.cc b/src/verifier/register_line.cc
index 544a9ee..3a2145b9 100644
--- a/src/verifier/register_line.cc
+++ b/src/verifier/register_line.cc
@@ -16,7 +16,9 @@
 
 #include "register_line.h"
 
+#include "dex_instruction-inl.h"
 #include "method_verifier.h"
+#include "register_line-inl.h"
 
 namespace art {
 namespace verifier {
@@ -92,22 +94,18 @@
   result_[1] = new_type2.GetId();
 }
 
-const RegType& RegisterLine::GetRegisterType(uint32_t vsrc) const {
-  // The register index was validated during the static pass, so we don't need to check it here.
-  DCHECK_LT(vsrc, num_regs_);
-  return verifier_->GetRegTypeCache()->GetFromId(line_[vsrc]);
-}
-
-const RegType& RegisterLine::GetInvocationThis(const DecodedInstruction& dec_insn) {
-  if (dec_insn.vA < 1) {
+const RegType& RegisterLine::GetInvocationThis(const Instruction* inst, bool is_range) {
+  const size_t args_count = is_range ? inst->VRegA_3rc() : inst->VRegA_35c();
+  if (args_count < 1) {
     verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invoke lacks 'this'";
     return verifier_->GetRegTypeCache()->Conflict();
   }
   /* get the element type of the array held in vsrc */
-  const RegType& this_type = GetRegisterType(dec_insn.vC);
+  const uint32_t this_reg = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
+  const RegType& this_type = GetRegisterType(this_reg);
   if (!this_type.IsReferenceTypes()) {
     verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "tried to get class from non-reference register v"
-                                                 << dec_insn.vC << " (type=" << this_type << ")";
+                                                 << this_reg << " (type=" << this_type << ")";
     return verifier_->GetRegTypeCache()->Conflict();
   }
   return this_type;
@@ -260,125 +258,135 @@
   }
 }
 
-void RegisterLine::CheckUnaryOp(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckUnaryOp(const Instruction* inst,
                                 const RegType& dst_type,
                                 const RegType& src_type) {
-  if (VerifyRegisterType(dec_insn.vB, src_type)) {
-    SetRegisterType(dec_insn.vA, dst_type);
+  if (VerifyRegisterType(inst->VRegB_12x(), src_type)) {
+    SetRegisterType(inst->VRegA_12x(), dst_type);
   }
 }
 
-void RegisterLine::CheckUnaryOpWide(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckUnaryOpWide(const Instruction* inst,
                                     const RegType& dst_type1, const RegType& dst_type2,
                                     const RegType& src_type1, const RegType& src_type2) {
-  if (VerifyRegisterTypeWide(dec_insn.vB, src_type1, src_type2)) {
-    SetRegisterTypeWide(dec_insn.vA, dst_type1, dst_type2);
+  if (VerifyRegisterTypeWide(inst->VRegB_12x(), src_type1, src_type2)) {
+    SetRegisterTypeWide(inst->VRegA_12x(), dst_type1, dst_type2);
   }
 }
 
-void RegisterLine::CheckUnaryOpToWide(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckUnaryOpToWide(const Instruction* inst,
                                       const RegType& dst_type1, const RegType& dst_type2,
                                       const RegType& src_type) {
-  if (VerifyRegisterType(dec_insn.vB, src_type)) {
-    SetRegisterTypeWide(dec_insn.vA, dst_type1, dst_type2);
+  if (VerifyRegisterType(inst->VRegB_12x(), src_type)) {
+    SetRegisterTypeWide(inst->VRegA_12x(), dst_type1, dst_type2);
   }
 }
 
-void RegisterLine::CheckUnaryOpFromWide(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckUnaryOpFromWide(const Instruction* inst,
                                         const RegType& dst_type,
                                         const RegType& src_type1, const RegType& src_type2) {
-  if (VerifyRegisterTypeWide(dec_insn.vB, src_type1, src_type2)) {
-    SetRegisterType(dec_insn.vA, dst_type);
+  if (VerifyRegisterTypeWide(inst->VRegB_12x(), src_type1, src_type2)) {
+    SetRegisterType(inst->VRegA_12x(), dst_type);
   }
 }
 
-void RegisterLine::CheckBinaryOp(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckBinaryOp(const Instruction* inst,
                                  const RegType& dst_type,
                                  const RegType& src_type1, const RegType& src_type2,
                                  bool check_boolean_op) {
-  if (VerifyRegisterType(dec_insn.vB, src_type1) &&
-      VerifyRegisterType(dec_insn.vC, src_type2)) {
+  const uint32_t vregB = inst->VRegB_23x();
+  const uint32_t vregC = inst->VRegC_23x();
+  if (VerifyRegisterType(vregB, src_type1) &&
+      VerifyRegisterType(vregC, src_type2)) {
     if (check_boolean_op) {
       DCHECK(dst_type.IsInteger());
-      if (GetRegisterType(dec_insn.vB).IsBooleanTypes() &&
-          GetRegisterType(dec_insn.vC).IsBooleanTypes()) {
-        SetRegisterType(dec_insn.vA, verifier_->GetRegTypeCache()->Boolean());
+      if (GetRegisterType(vregB).IsBooleanTypes() &&
+          GetRegisterType(vregC).IsBooleanTypes()) {
+        SetRegisterType(inst->VRegA_23x(), verifier_->GetRegTypeCache()->Boolean());
         return;
       }
     }
-    SetRegisterType(dec_insn.vA, dst_type);
+    SetRegisterType(inst->VRegA_23x(), dst_type);
   }
 }
 
-void RegisterLine::CheckBinaryOpWide(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckBinaryOpWide(const Instruction* inst,
                                      const RegType& dst_type1, const RegType& dst_type2,
                                      const RegType& src_type1_1, const RegType& src_type1_2,
                                      const RegType& src_type2_1, const RegType& src_type2_2) {
-  if (VerifyRegisterTypeWide(dec_insn.vB, src_type1_1, src_type1_2) &&
-      VerifyRegisterTypeWide(dec_insn.vC, src_type2_1, src_type2_2)) {
-    SetRegisterTypeWide(dec_insn.vA, dst_type1, dst_type2);
+  if (VerifyRegisterTypeWide(inst->VRegB_23x(), src_type1_1, src_type1_2) &&
+      VerifyRegisterTypeWide(inst->VRegC_23x(), src_type2_1, src_type2_2)) {
+    SetRegisterTypeWide(inst->VRegA_23x(), dst_type1, dst_type2);
   }
 }
 
-void RegisterLine::CheckBinaryOpWideShift(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckBinaryOpWideShift(const Instruction* inst,
                                           const RegType& long_lo_type, const RegType& long_hi_type,
                                           const RegType& int_type) {
-  if (VerifyRegisterTypeWide(dec_insn.vB, long_lo_type, long_hi_type) &&
-      VerifyRegisterType(dec_insn.vC, int_type)) {
-    SetRegisterTypeWide(dec_insn.vA, long_lo_type, long_hi_type);
+  if (VerifyRegisterTypeWide(inst->VRegB_23x(), long_lo_type, long_hi_type) &&
+      VerifyRegisterType(inst->VRegC_23x(), int_type)) {
+    SetRegisterTypeWide(inst->VRegA_23x(), long_lo_type, long_hi_type);
   }
 }
 
-void RegisterLine::CheckBinaryOp2addr(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckBinaryOp2addr(const Instruction* inst,
                                       const RegType& dst_type, const RegType& src_type1,
                                       const RegType& src_type2, bool check_boolean_op) {
-  if (VerifyRegisterType(dec_insn.vA, src_type1) &&
-      VerifyRegisterType(dec_insn.vB, src_type2)) {
+  const uint32_t vregA = inst->VRegA_12x();
+  const uint32_t vregB = inst->VRegB_12x();
+  if (VerifyRegisterType(vregA, src_type1) &&
+      VerifyRegisterType(vregB, src_type2)) {
     if (check_boolean_op) {
       DCHECK(dst_type.IsInteger());
-      if (GetRegisterType(dec_insn.vA).IsBooleanTypes() &&
-          GetRegisterType(dec_insn.vB).IsBooleanTypes()) {
-        SetRegisterType(dec_insn.vA, verifier_->GetRegTypeCache()->Boolean());
+      if (GetRegisterType(vregA).IsBooleanTypes() &&
+          GetRegisterType(vregB).IsBooleanTypes()) {
+        SetRegisterType(vregA, verifier_->GetRegTypeCache()->Boolean());
         return;
       }
     }
-    SetRegisterType(dec_insn.vA, dst_type);
+    SetRegisterType(vregA, dst_type);
   }
 }
 
-void RegisterLine::CheckBinaryOp2addrWide(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckBinaryOp2addrWide(const Instruction* inst,
                                           const RegType& dst_type1, const RegType& dst_type2,
                                           const RegType& src_type1_1, const RegType& src_type1_2,
                                           const RegType& src_type2_1, const RegType& src_type2_2) {
-  if (VerifyRegisterTypeWide(dec_insn.vA, src_type1_1, src_type1_2) &&
-      VerifyRegisterTypeWide(dec_insn.vB, src_type2_1, src_type2_2)) {
-    SetRegisterTypeWide(dec_insn.vA, dst_type1, dst_type2);
+  const uint32_t vregA = inst->VRegA_12x();
+  const uint32_t vregB = inst->VRegB_12x();
+  if (VerifyRegisterTypeWide(vregA, src_type1_1, src_type1_2) &&
+      VerifyRegisterTypeWide(vregB, src_type2_1, src_type2_2)) {
+    SetRegisterTypeWide(vregA, dst_type1, dst_type2);
   }
 }
 
-void RegisterLine::CheckBinaryOp2addrWideShift(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckBinaryOp2addrWideShift(const Instruction* inst,
                                                const RegType& long_lo_type, const RegType& long_hi_type,
                                                const RegType& int_type) {
-  if (VerifyRegisterTypeWide(dec_insn.vA, long_lo_type, long_hi_type) &&
-      VerifyRegisterType(dec_insn.vB, int_type)) {
-    SetRegisterTypeWide(dec_insn.vA, long_lo_type, long_hi_type);
+  const uint32_t vregA = inst->VRegA_12x();
+  const uint32_t vregB = inst->VRegB_12x();
+  if (VerifyRegisterTypeWide(vregA, long_lo_type, long_hi_type) &&
+      VerifyRegisterType(vregB, int_type)) {
+    SetRegisterTypeWide(vregA, long_lo_type, long_hi_type);
   }
 }
 
-void RegisterLine::CheckLiteralOp(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckLiteralOp(const Instruction* inst,
                                   const RegType& dst_type, const RegType& src_type,
-                                  bool check_boolean_op) {
-  if (VerifyRegisterType(dec_insn.vB, src_type)) {
+                                  bool check_boolean_op, bool is_lit16) {
+  const uint32_t vregA = is_lit16 ? inst->VRegA_22s() : inst->VRegA_22b();
+  const uint32_t vregB = is_lit16 ? inst->VRegB_22s() : inst->VRegB_22b();
+  if (VerifyRegisterType(vregB, src_type)) {
     if (check_boolean_op) {
       DCHECK(dst_type.IsInteger());
       /* check vB with the call, then check the constant manually */
-      if (GetRegisterType(dec_insn.vB).IsBooleanTypes() &&
-          (dec_insn.vC == 0 || dec_insn.vC == 1)) {
-        SetRegisterType(dec_insn.vA, verifier_->GetRegTypeCache()->Boolean());
+      const uint32_t val = is_lit16 ? inst->VRegC_22s() : inst->VRegC_22b();
+      if (GetRegisterType(vregB).IsBooleanTypes() && (val == 0 || val == 1)) {
+        SetRegisterType(vregA, verifier_->GetRegTypeCache()->Boolean());
         return;
       }
     }
-    SetRegisterType(dec_insn.vA, dst_type);
+    SetRegisterType(vregA, dst_type);
   }
 }
 
@@ -427,6 +435,8 @@
 
 bool RegisterLine::MergeRegisters(const RegisterLine* incoming_line) {
   bool changed = false;
+  CHECK(NULL != incoming_line);
+  CHECK(NULL != line_.get());
   for (size_t idx = 0; idx < num_regs_; idx++) {
     if (line_[idx] != incoming_line->line_[idx]) {
       const RegType& incoming_reg_type = incoming_line->GetRegisterType(idx);
diff --git a/src/verifier/register_line.h b/src/verifier/register_line.h
index 5719082..5f17049 100644
--- a/src/verifier/register_line.h
+++ b/src/verifier/register_line.h
@@ -169,28 +169,28 @@
    * The argument count is in vA, and the first argument is in vC, for both "simple" and "range"
    * versions. We just need to make sure vA is >= 1 and then return vC.
    */
-  const RegType& GetInvocationThis(const DecodedInstruction& dec_insn)
+  const RegType& GetInvocationThis(const Instruction* inst, bool is_range)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   /*
    * Verify types for a simple two-register instruction (e.g. "neg-int").
    * "dst_type" is stored into vA, and "src_type" is verified against vB.
    */
-  void CheckUnaryOp(const DecodedInstruction& dec_insn,
-                    const RegType& dst_type, const RegType& src_type)
+  void CheckUnaryOp(const Instruction* inst, const RegType& dst_type,
+                    const RegType& src_type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void CheckUnaryOpWide(const DecodedInstruction& dec_insn,
+  void CheckUnaryOpWide(const Instruction* inst,
                         const RegType& dst_type1, const RegType& dst_type2,
                         const RegType& src_type1, const RegType& src_type2)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void CheckUnaryOpToWide(const DecodedInstruction& dec_insn,
+  void CheckUnaryOpToWide(const Instruction* inst,
                           const RegType& dst_type1, const RegType& dst_type2,
                           const RegType& src_type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void CheckUnaryOpFromWide(const DecodedInstruction& dec_insn,
+  void CheckUnaryOpFromWide(const Instruction* inst,
                             const RegType& dst_type,
                             const RegType& src_type1, const RegType& src_type2)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -200,18 +200,18 @@
    * "dst_type" is stored into vA, and "src_type1"/"src_type2" are verified
    * against vB/vC.
    */
-  void CheckBinaryOp(const DecodedInstruction& dec_insn,
+  void CheckBinaryOp(const Instruction* inst,
                      const RegType& dst_type, const RegType& src_type1, const RegType& src_type2,
                      bool check_boolean_op)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void CheckBinaryOpWide(const DecodedInstruction& dec_insn,
+  void CheckBinaryOpWide(const Instruction* inst,
                          const RegType& dst_type1, const RegType& dst_type2,
                          const RegType& src_type1_1, const RegType& src_type1_2,
                          const RegType& src_type2_1, const RegType& src_type2_2)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void CheckBinaryOpWideShift(const DecodedInstruction& dec_insn,
+  void CheckBinaryOpWideShift(const Instruction* inst,
                               const RegType& long_lo_type, const RegType& long_hi_type,
                               const RegType& int_type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -220,19 +220,19 @@
    * Verify types for a binary "2addr" operation. "src_type1"/"src_type2"
    * are verified against vA/vB, then "dst_type" is stored into vA.
    */
-  void CheckBinaryOp2addr(const DecodedInstruction& dec_insn,
+  void CheckBinaryOp2addr(const Instruction* inst,
                           const RegType& dst_type,
                           const RegType& src_type1, const RegType& src_type2,
                           bool check_boolean_op)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void CheckBinaryOp2addrWide(const DecodedInstruction& dec_insn,
+  void CheckBinaryOp2addrWide(const Instruction* inst,
                               const RegType& dst_type1, const RegType& dst_type2,
                               const RegType& src_type1_1, const RegType& src_type1_2,
                               const RegType& src_type2_1, const RegType& src_type2_2)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void CheckBinaryOp2addrWideShift(const DecodedInstruction& dec_insn,
+  void CheckBinaryOp2addrWideShift(const Instruction* inst,
                                    const RegType& long_lo_type, const RegType& long_hi_type,
                                    const RegType& int_type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -243,8 +243,9 @@
    *
    * If "check_boolean_op" is set, we use the constant value in vC.
    */
-  void CheckLiteralOp(const DecodedInstruction& dec_insn,
-                      const RegType& dst_type, const RegType& src_type, bool check_boolean_op)
+  void CheckLiteralOp(const Instruction* inst,
+                      const RegType& dst_type, const RegType& src_type,
+                      bool check_boolean_op, bool is_lit16)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Verify/push monitor onto the monitor stack, locking the value in reg_idx at location insn_idx.
diff --git a/test/031-class-attributes/expected.txt b/test/031-class-attributes/expected.txt
index afa3416..4ae1eed 100644
--- a/test/031-class-attributes/expected.txt
+++ b/test/031-class-attributes/expected.txt
@@ -1,3 +1,25 @@
+public abstract final int
+public abstract final [I
+public java.lang.Object
+public abstract final [Ljava.lang.Object;
+public ClassAttrs$PublicInnerClass
+public abstract final [LClassAttrs$PublicInnerClass;
+protected ClassAttrs$ProtectedInnerClass
+protected abstract final [LClassAttrs$ProtectedInnerClass;
+private ClassAttrs$PrivateInnerClass
+private abstract final [LClassAttrs$PrivateInnerClass;
+ ClassAttrs$PackagePrivateInnerClass
+abstract final [LClassAttrs$PackagePrivateInnerClass;
+public abstract interface java.io.Serializable
+public abstract final [Ljava.io.Serializable;
+public abstract static interface ClassAttrs$PublicInnerInterface
+public abstract final [LClassAttrs$PublicInnerInterface;
+protected abstract static interface ClassAttrs$ProtectedInnerInterface
+protected abstract final [LClassAttrs$ProtectedInnerInterface;
+private abstract static interface ClassAttrs$PrivateInnerInterface
+private abstract final [LClassAttrs$PrivateInnerInterface;
+abstract static interface ClassAttrs$PackagePrivateInnerInterface
+abstract final [LClassAttrs$PackagePrivateInnerInterface;
 ***** class ClassAttrs:
   name: ClassAttrs
   canonical: ClassAttrs
@@ -11,8 +33,8 @@
   enclosingMeth: null
   modifiers: 1
   package: null
-  declaredClasses: [2] class ClassAttrs$PublicMemberClass, class ClassAttrs$MemberClass
-  member classes: [1] class ClassAttrs$PublicMemberClass
+  declaredClasses: [10] class ClassAttrs$PublicMemberClass, class ClassAttrs$MemberClass, interface ClassAttrs$PackagePrivateInnerInterface, interface ClassAttrs$PrivateInnerInterface, interface ClassAttrs$ProtectedInnerInterface, interface ClassAttrs$PublicInnerInterface, class ClassAttrs$PackagePrivateInnerClass, class ClassAttrs$PrivateInnerClass, class ClassAttrs$ProtectedInnerClass, class ClassAttrs$PublicInnerClass
+  member classes: [3] class ClassAttrs$PublicMemberClass, interface ClassAttrs$PublicInnerInterface, class ClassAttrs$PublicInnerClass
   isAnnotation: false
   isAnonymous: false
   isArray: false
diff --git a/test/031-class-attributes/src/ClassAttrs.java b/test/031-class-attributes/src/ClassAttrs.java
index 8719e3b..ae8b2f5 100644
--- a/test/031-class-attributes/src/ClassAttrs.java
+++ b/test/031-class-attributes/src/ClassAttrs.java
@@ -1,10 +1,12 @@
 import otherpackage.OtherPackageClass;
 
+import java.io.Serializable;
 import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.lang.reflect.Type;
 import java.lang.reflect.TypeVariable;
 
@@ -21,7 +23,72 @@
         cinner.showMe();
     }
 
+    public class PublicInnerClass {
+    }
+
+    protected class ProtectedInnerClass {
+    }
+
+    private class PrivateInnerClass {
+    }
+
+    class PackagePrivateInnerClass {
+    }
+
+    public interface PublicInnerInterface {
+    }
+
+    protected interface ProtectedInnerInterface {
+    }
+
+    private interface PrivateInnerInterface {
+    }
+
+    interface PackagePrivateInnerInterface {
+    }
+
+    private static void showModifiers(Class<?> c) {
+        System.out.println(Modifier.toString(c.getModifiers()) + " " + c.getName());
+    }
+
+    // https://code.google.com/p/android/issues/detail?id=56267
+    private static void test56267() {
+        // Primitive classes.
+        showModifiers(int.class);
+        showModifiers(int[].class);
+
+        // Regular classes.
+        showModifiers(Object.class);
+        showModifiers(Object[].class);
+
+        // Inner classes.
+        showModifiers(PublicInnerClass.class);
+        showModifiers(PublicInnerClass[].class);
+        showModifiers(ProtectedInnerClass.class);
+        showModifiers(ProtectedInnerClass[].class);
+        showModifiers(PrivateInnerClass.class);
+        showModifiers(PrivateInnerClass[].class);
+        showModifiers(PackagePrivateInnerClass.class);
+        showModifiers(PackagePrivateInnerClass[].class);
+
+        // Regular interfaces.
+        showModifiers(Serializable.class);
+        showModifiers(Serializable[].class);
+
+        // Inner interfaces.
+        showModifiers(PublicInnerInterface.class);
+        showModifiers(PublicInnerInterface[].class);
+        showModifiers(ProtectedInnerInterface.class);
+        showModifiers(ProtectedInnerInterface[].class);
+        showModifiers(PrivateInnerInterface.class);
+        showModifiers(PrivateInnerInterface[].class);
+        showModifiers(PackagePrivateInnerInterface.class);
+        showModifiers(PackagePrivateInnerInterface[].class);
+    }
+
     public static void main() {
+        test56267();
+
         printClassAttrs(ClassAttrs.class);
         printClassAttrs(OtherClass.class);
         printClassAttrs(OtherPackageClass.class);
diff --git a/test/045-reflect-array/expected.txt b/test/045-reflect-array/expected.txt
index 5990b34..b9a98c9 100644
--- a/test/045-reflect-array/expected.txt
+++ b/test/045-reflect-array/expected.txt
@@ -6,4 +6,7 @@
 ReflectArrayTest.testMultiInt passed
 zero one two ++
 ReflectArrayTest.testMulti passed
+class [Ljava.lang.Number; modifiers: 1041
+class [Ljava.lang.Cloneable; modifiers: 1041
+ReflectArrayTest.testAbstract passed
 ReflectArrayTest passed
diff --git a/test/045-reflect-array/src/Main.java b/test/045-reflect-array/src/Main.java
index 05cf843..7418eed 100644
--- a/test/045-reflect-array/src/Main.java
+++ b/test/045-reflect-array/src/Main.java
@@ -16,6 +16,7 @@
         testSingle();
         testMultiInt();
         testMulti();
+        testAbstract();
 
         System.out.println("ReflectArrayTest passed");
     }
@@ -255,4 +256,14 @@
         }
         System.out.println("ReflectArrayTest.testMulti passed");
     }
+
+    static void testAbstract() {
+        Object arrayOfAbstractClasses = Array.newInstance(Number.class, 1);
+        System.out.println(arrayOfAbstractClasses.getClass().toString() + " modifiers: " +
+                           arrayOfAbstractClasses.getClass().getModifiers());
+        arrayOfAbstractClasses = Array.newInstance(Cloneable.class, 1);
+        System.out.println(arrayOfAbstractClasses.getClass().toString() + " modifiers: " +
+                           arrayOfAbstractClasses.getClass().getModifiers());
+        System.out.println("ReflectArrayTest.testAbstract passed");
+    }
 }
diff --git a/test/100-reflect2/expected.txt b/test/100-reflect2/expected.txt
index 0c567d4..f56fd98 100644
--- a/test/100-reflect2/expected.txt
+++ b/test/100-reflect2/expected.txt
@@ -34,7 +34,7 @@
 30 (class java.lang.Integer)
 62 (class java.lang.Long)
 14 (class java.lang.Short)
-[public java.lang.String(), java.lang.String(int,int,char[]), public java.lang.String(java.lang.String), private java.lang.String(java.lang.String,char), private java.lang.String(java.lang.String,int), private java.lang.String(java.lang.String,java.lang.String), private java.lang.String(java.lang.String,java.lang.String,java.lang.String), public java.lang.String(java.lang.StringBuffer), public java.lang.String(java.lang.StringBuilder), public java.lang.String(byte[]), public java.lang.String(byte[],int), public java.lang.String(byte[],int,int), public java.lang.String(byte[],int,int,int), public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],int,int,java.nio.charset.Charset), public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],java.nio.charset.Charset), public java.lang.String(char[]), public java.lang.String(char[],int,int), public java.lang.String(int[],int,int)]
+[public java.lang.String(), java.lang.String(int,int,char[]), public java.lang.String(java.lang.String), public java.lang.String(java.lang.StringBuffer), public java.lang.String(java.lang.StringBuilder), public java.lang.String(byte[]), public java.lang.String(byte[],int), public java.lang.String(byte[],int,int), public java.lang.String(byte[],int,int,int), public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],int,int,java.nio.charset.Charset), public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],java.nio.charset.Charset), public java.lang.String(char[]), public java.lang.String(char[],int,int), public java.lang.String(int[],int,int)]
 [private final char[] java.lang.String.value, private final int java.lang.String.count, private int java.lang.String.hashCode, private final int java.lang.String.offset, private static final char[] java.lang.String.ASCII, public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER, private static final char java.lang.String.REPLACEMENT_CHAR, private static final long java.lang.String.serialVersionUID]
 [void java.lang.String._getChars(int,int,char[],int), public char java.lang.String.charAt(int), public int java.lang.String.codePointAt(int), public int java.lang.String.codePointBefore(int), public int java.lang.String.codePointCount(int,int), public volatile int java.lang.String.compareTo(java.lang.Object), public native int java.lang.String.compareTo(java.lang.String), public int java.lang.String.compareToIgnoreCase(java.lang.String), public java.lang.String java.lang.String.concat(java.lang.String), public boolean java.lang.String.contains(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.StringBuffer), public boolean java.lang.String.endsWith(java.lang.String), public boolean java.lang.String.equals(java.lang.Object), public boolean java.lang.String.equalsIgnoreCase(java.lang.String), public void java.lang.String.getBytes(int,int,byte[],int), public [B java.lang.String.getBytes(), public [B java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException, public [B java.lang.String.getBytes(java.nio.charset.Charset), public void java.lang.String.getChars(int,int,char[],int), public int java.lang.String.hashCode(), public int java.lang.String.indexOf(int), public int java.lang.String.indexOf(int,int), public int java.lang.String.indexOf(java.lang.String), public int java.lang.String.indexOf(java.lang.String,int), public native java.lang.String java.lang.String.intern(), public boolean java.lang.String.isEmpty(), public int java.lang.String.lastIndexOf(int), public int java.lang.String.lastIndexOf(int,int), public int java.lang.String.lastIndexOf(java.lang.String), public int java.lang.String.lastIndexOf(java.lang.String,int), public int java.lang.String.length(), public boolean java.lang.String.matches(java.lang.String), public int java.lang.String.offsetByCodePoints(int,int), public boolean java.lang.String.regionMatches(int,java.lang.String,int,int), public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int), public java.lang.String java.lang.String.replace(char,char), public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence), public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String), public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String), public [Ljava.lang.String; java.lang.String.split(java.lang.String), public [Ljava.lang.String; java.lang.String.split(java.lang.String,int), public boolean java.lang.String.startsWith(java.lang.String), public boolean java.lang.String.startsWith(java.lang.String,int), public java.lang.CharSequence java.lang.String.subSequence(int,int), public java.lang.String java.lang.String.substring(int), public java.lang.String java.lang.String.substring(int,int), public [C java.lang.String.toCharArray(), public java.lang.String java.lang.String.toLowerCase(), public java.lang.String java.lang.String.toLowerCase(java.util.Locale), public java.lang.String java.lang.String.toString(), public java.lang.String java.lang.String.toUpperCase(), public java.lang.String java.lang.String.toUpperCase(java.util.Locale), public java.lang.String java.lang.String.trim(), static void java.lang.String.<clinit>(), public static java.lang.String java.lang.String.copyValueOf(char[]), public static java.lang.String java.lang.String.copyValueOf(char[],int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.failedBoundsCheck(int,int,int), private native int java.lang.String.fastIndexOf(int,int), private char java.lang.String.foldCase(char), public static transient java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[]), public static transient java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[]), private java.lang.StringIndexOutOfBoundsException java.lang.String.indexAndLength(int), private static int java.lang.String.indexOf(java.lang.String,java.lang.String,int,int,char), private int java.lang.String.indexOfSupplementary(int,int), private int java.lang.String.lastIndexOfSupplementary(int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.startEndAndLength(int,int), public static java.lang.String java.lang.String.valueOf(char), public static java.lang.String java.lang.String.valueOf(double), public static java.lang.String java.lang.String.valueOf(float), public static java.lang.String java.lang.String.valueOf(int), public static java.lang.String java.lang.String.valueOf(long), public static java.lang.String java.lang.String.valueOf(java.lang.Object), public static java.lang.String java.lang.String.valueOf(boolean), public static java.lang.String java.lang.String.valueOf(char[]), public static java.lang.String java.lang.String.valueOf(char[],int,int)]
 []
diff --git a/test/108-check-cast/expected.txt b/test/108-check-cast/expected.txt
new file mode 100644
index 0000000..d86bac9
--- /dev/null
+++ b/test/108-check-cast/expected.txt
@@ -0,0 +1 @@
+OK
diff --git a/test/108-check-cast/info.txt b/test/108-check-cast/info.txt
new file mode 100644
index 0000000..e7ffa4f
--- /dev/null
+++ b/test/108-check-cast/info.txt
@@ -0,0 +1,10 @@
+This test relies on the correct behavior of instance-of to test check-cast behavior,
+as shown below:
+
+
+CCE throw| InstanceOf | Correct?
+---------+------------+----------
+      1  |     0      |    OK
+      1  |     1      |    BAD
+      0  |     0      |    BAD
+      0  |     1      |    OK
\ No newline at end of file
diff --git a/test/108-check-cast/src/Main.java b/test/108-check-cast/src/Main.java
new file mode 100644
index 0000000..7ef13fd
--- /dev/null
+++ b/test/108-check-cast/src/Main.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+/**
+ * Testing check-cast, see comment in info.txt
+ */
+
+class B {}
+class D extends B {}
+
+public class Main {
+    public static void main(String args[]) {
+        B b = null;
+        try {
+            if (1 == args.length) {
+                b = new B();
+            } else {
+                b = new D();
+            }
+            D d = (D) b;
+            if (!(b instanceof D)) {
+                System.out.println("Error: No ClassCastException throuwn when it should have been.");
+            } else {
+                System.out.println("OK");
+            }
+        }
+        catch (ClassCastException cce) {
+            if (b instanceof D) {
+                System.out.println("Error: ClassCastException thrown when it shouldn't have been.");
+            } else {
+                System.out.println("OK");
+            }
+        }
+    }
+}