Merge "Fix JDWP Virtualmachine.Resume command"
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index 14edb71..478c63c 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -93,8 +93,8 @@
 #
 # Used to change the default GC. Valid values are CMS, SS, GSS. The default is CMS.
 #
-ART_DEFAULT_GC_TYPE ?= CMS
-ART_DEFAULT_GC_TYPE_CFLAGS := -DART_DEFAULT_GC_TYPE_IS_$(ART_DEFAULT_GC_TYPE)
+art_default_gc_type ?= CMS
+art_default_gc_type_cflags := -DART_DEFAULT_GC_TYPE_IS_$(art_default_gc_type)
 
 ifeq ($(ART_USE_PORTABLE_COMPILER),true)
   LLVM_ROOT_PATH := external/llvm
@@ -102,6 +102,9 @@
   -include $(LLVM_ROOT_PATH)/llvm.mk
 endif
 
+ART_HOST_CFLAGS :=
+ART_TARGET_CFLAGS :=
+
 # Clang build support.
 
 # Host.
@@ -131,30 +134,6 @@
       endif)
 endef
 
-ART_CPP_EXTENSION := .cc
-
-ART_C_INCLUDES := \
-  external/gtest/include \
-  external/valgrind/main/include \
-  external/valgrind/main \
-  external/vixl/src \
-  external/zlib \
-  frameworks/compile/mclinker/include
-
-art_cflags := \
-  -fno-rtti \
-  -std=gnu++11 \
-  -ggdb3 \
-  -Wall \
-  -Werror \
-  -Wextra \
-  -Wno-sign-promo \
-  -Wno-unused-parameter \
-  -Wstrict-aliasing \
-  -fstrict-aliasing \
-  -Wunreachable-code \
-  -fvisibility=protected
-
 ART_TARGET_CLANG_CFLAGS :=
 ART_TARGET_CLANG_CFLAGS_arm :=
 ART_TARGET_CLANG_CFLAGS_arm64 :=
@@ -168,6 +147,58 @@
   -DNVALGRIND \
   -Wno-unused-value
 
+# FIXME: upstream LLVM has a vectorizer bug that needs to be fixed
+ART_TARGET_CLANG_CFLAGS_arm64 += \
+  -fno-vectorize
+
+# Colorize clang compiler warnings.
+art_clang_cflags := -fcolor-diagnostics
+
+# Warn about thread safety violations with clang.
+art_clang_cflags += -Wthread-safety
+
+# Warn if switch fallthroughs aren't annotated.
+art_clang_cflags += -Wimplicit-fallthrough
+
+# Enable float equality warnings.
+art_clang_cflags += -Wfloat-equal
+
+ifeq ($(ART_HOST_CLANG),true)
+  ART_HOST_CFLAGS += $(art_clang_cflags)
+endif
+ifeq ($(ART_TARGET_CLANG),true)
+  ART_TARGET_CFLAGS += $(art_clang_cflags)
+endif
+
+# Clear local variable now its use has ended.
+art_clang_cflags :=
+
+ART_CPP_EXTENSION := .cc
+
+ART_C_INCLUDES := \
+  external/gtest/include \
+  external/valgrind/main/include \
+  external/valgrind/main \
+  external/vixl/src \
+  external/zlib \
+  frameworks/compile/mclinker/include
+
+# Base set of cflags used by all things ART.
+art_cflags := \
+  -fno-rtti \
+  -std=gnu++11 \
+  -ggdb3 \
+  -Wall \
+  -Werror \
+  -Wextra \
+  -Wno-sign-promo \
+  -Wno-unused-parameter \
+  -Wstrict-aliasing \
+  -fstrict-aliasing \
+  -Wunreachable-code \
+  -fvisibility=protected \
+  $(art_default_gc_type_cflags)
+
 ifeq ($(ART_SMALL_MODE),true)
   art_cflags += -DART_SMALL_MODE=1
 endif
@@ -176,14 +207,18 @@
   art_cflags += -DART_SEA_IR_MODE=1
 endif
 
+# Cflags for non-debug ART and ART tools.
 art_non_debug_cflags := \
   -O3
 
-art_host_non_debug_cflags := \
-  $(art_non_debug_cflags)
+# Cflags for debug ART and ART tools.
+art_debug_cflags := \
+  -O2 \
+  -DDYNAMIC_ANNOTATIONS_ENABLED=1 \
+  -UNDEBUG
 
-art_target_non_debug_cflags := \
-  $(art_non_debug_cflags)
+art_host_non_debug_cflags := $(art_non_debug_cflags)
+art_target_non_debug_cflags := $(art_non_debug_cflags)
 
 ifeq ($(HOST_OS),linux)
   # Larger frame-size for host clang builds today
@@ -191,26 +226,21 @@
   art_target_non_debug_cflags += -Wframe-larger-than=1728
 endif
 
-# FIXME: upstream LLVM has a vectorizer bug that needs to be fixed
-ART_TARGET_CLANG_CFLAGS_arm64 += \
-  -fno-vectorize
-
-art_debug_cflags := \
-  -O2 \
-  -DDYNAMIC_ANNOTATIONS_ENABLED=1 \
-  -UNDEBUG
-
 ifndef LIBART_IMG_HOST_BASE_ADDRESS
   $(error LIBART_IMG_HOST_BASE_ADDRESS unset)
 endif
-ART_HOST_CFLAGS := $(art_cflags) -DANDROID_SMP=1 -DART_BASE_ADDRESS=$(LIBART_IMG_HOST_BASE_ADDRESS)
+ART_HOST_CFLAGS += $(art_cflags) -DANDROID_SMP=1 -DART_BASE_ADDRESS=$(LIBART_IMG_HOST_BASE_ADDRESS)
 ART_HOST_CFLAGS += -DART_DEFAULT_INSTRUCTION_SET_FEATURES=default
-ART_HOST_CFLAGS += $(ART_DEFAULT_GC_TYPE_CFLAGS)
 
 ifndef LIBART_IMG_TARGET_BASE_ADDRESS
   $(error LIBART_IMG_TARGET_BASE_ADDRESS unset)
 endif
-ART_TARGET_CFLAGS := $(art_cflags) -DART_TARGET -DART_BASE_ADDRESS=$(LIBART_IMG_TARGET_BASE_ADDRESS)
+ART_TARGET_CFLAGS += $(art_cflags) -DART_TARGET -DART_BASE_ADDRESS=$(LIBART_IMG_TARGET_BASE_ADDRESS)
+
+ART_HOST_NON_DEBUG_CFLAGS := $(art_host_non_debug_cflags)
+ART_TARGET_NON_DEBUG_CFLAGS := $(art_target_non_debug_cflags)
+ART_HOST_DEBUG_CFLAGS := $(art_debug_cflags)
+ART_TARGET_DEBUG_CFLAGS := $(art_debug_cflags)
 
 ifndef LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA
   LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA=-0x1000000
@@ -230,25 +260,6 @@
 ART_TARGET_CFLAGS += -DART_BASE_ADDRESS_MIN_DELTA=$(LIBART_IMG_TARGET_MIN_BASE_ADDRESS_DELTA)
 ART_TARGET_CFLAGS += -DART_BASE_ADDRESS_MAX_DELTA=$(LIBART_IMG_TARGET_MAX_BASE_ADDRESS_DELTA)
 
-# Colorize clang compiler warnings.
-art_clang_cflags := -fcolor-diagnostics
-
-# Warn if switch fallthroughs aren't annotated.
-art_clang_cflags += -Wimplicit-fallthrough
-
-# Enable float equality warnings.
-art_clang_cflags += -Wfloat-equal
-
-ifeq ($(ART_HOST_CLANG),true)
-  ART_HOST_CFLAGS += $(art_clang_cflags)
-endif
-ifeq ($(ART_TARGET_CLANG),true)
-  ART_TARGET_CFLAGS += $(art_clang_cflags)
-endif
-
-art_clang_cflags :=
-
-ART_TARGET_LDFLAGS :=
 ifeq ($(TARGET_CPU_SMP),true)
   ART_TARGET_CFLAGS += -DANDROID_SMP=1
 else
@@ -260,60 +271,26 @@
     ART_TARGET_CFLAGS += -DANDROID_SMP=1
   endif
 endif
-ART_TARGET_CFLAGS += $(ART_DEFAULT_GC_TYPE_CFLAGS)
-
-# DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES is set in ../build/core/dex_preopt.mk based on
-# the TARGET_CPU_VARIANT
-ifeq ($(DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES),)
-$(error Required DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES is not set)
-endif
-ART_TARGET_CFLAGS += -DART_DEFAULT_INSTRUCTION_SET_FEATURES=$(DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES)
-
-# Enable thread-safety for GCC 4.6, and clang, but not for GCC 4.7 or later where this feature was
-# removed. Warn when -Wthread-safety is not used.
-ifneq ($(filter 4.6 4.6.%, $(TARGET_GCC_VERSION)),)
-  ART_TARGET_CFLAGS += -Wthread-safety
-else
-  # FIXME: add -Wthread-safety when the problem is fixed
-  ifeq ($(ART_TARGET_CLANG),true)
-    ART_TARGET_CFLAGS +=
-  else
-    # Warn if -Wthread-safety is not supported and 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
-endif
-# We compile with GCC 4.6 or clang on the host, both of which support -Wthread-safety.
-ART_HOST_CFLAGS += -Wthread-safety
 
 # To use oprofile_android --callgraph, uncomment this and recompile with "mmm art -B -j16"
 # ART_TARGET_CFLAGS += -fno-omit-frame-pointer -marm -mapcs
 
-# Addition CPU specific CFLAGS.
-ifeq ($(TARGET_ARCH),arm)
-  ifneq ($(filter cortex-a15, $(TARGET_CPU_VARIANT)),)
-    # Fake a ARM feature for LPAE support.
-    ART_TARGET_CFLAGS += -D__ARM_FEATURE_LPAE=1
-  endif
+# Clear locals now they've served their purpose.
+art_cflags :=
+art_debug_cflags :=
+art_non_debug_cflags :=
+art_host_non_debug_cflags :=
+art_target_non_debug_cflags :=
+art_default_gc_type :=
+art_default_gc_type_cflags :=
+
+ART_HOST_LDLIBS :=
+ifneq ($(ART_HOST_CLANG),true)
+  # GCC lacks libc++ assumed atomic operations, grab via libatomic.
+  ART_HOST_LDLIBS += -latomic
 endif
 
-ART_HOST_NON_DEBUG_CFLAGS := $(art_host_non_debug_cflags)
-ART_TARGET_NON_DEBUG_CFLAGS := $(art_target_non_debug_cflags)
-
-# TODO: move -fkeep-inline-functions to art_debug_cflags when target gcc > 4.4 (and -lsupc++)
-ART_HOST_DEBUG_CFLAGS := $(art_debug_cflags) -fkeep-inline-functions
-ART_HOST_DEBUG_LDLIBS := -lsupc++
-
-ifneq ($(HOST_OS),linux)
-  # Some Mac OS pthread header files are broken with -fkeep-inline-functions.
-  ART_HOST_DEBUG_CFLAGS := $(filter-out -fkeep-inline-functions,$(ART_HOST_DEBUG_CFLAGS))
-  # Mac OS doesn't have libsupc++.
-  ART_HOST_DEBUG_LDLIBS := $(filter-out -lsupc++,$(ART_HOST_DEBUG_LDLIBS))
-endif
-
-ART_TARGET_DEBUG_CFLAGS := $(art_debug_cflags)
+ART_TARGET_LDFLAGS :=
 
 # $(1): ndebug_or_debug
 define set-target-local-cflags-vars
@@ -337,6 +314,7 @@
   art_target_cflags_ndebug_or_debug :=
 endef
 
+# Support for disabling certain builds.
 ART_BUILD_TARGET := false
 ART_BUILD_HOST := false
 ART_BUILD_NDEBUG := false
@@ -358,12 +336,4 @@
   ART_BUILD_DEBUG := true
 endif
 
-# Clear locally defined variables that aren't necessary in the rest of the build system.
-ART_DEFAULT_GC_TYPE :=
-ART_DEFAULT_GC_TYPE_CFLAGS :=
-art_cflags :=
-art_target_non_debug_cflags :=
-art_host_non_debug_cflags :=
-art_non_debug_cflags :=
-
 endif # ANDROID_COMMON_BUILD_MK
diff --git a/build/Android.common_test.mk b/build/Android.common_test.mk
index ee72706..3e76d91 100644
--- a/build/Android.common_test.mk
+++ b/build/Android.common_test.mk
@@ -90,6 +90,12 @@
 # Do you want run-tests without a dex2oat?
 ART_TEST_RUN_TEST_NO_DEX2OAT ?= $(ART_TEST_FULL)
 
+# Do you want run-tests with libartd.so?
+ART_TEST_RUN_TEST_DEBUG ?= true
+
+# Do you want run-tests with libart.so?
+ART_TEST_RUN_TEST_NDEBUG ?= $(ART_TEST_FULL)
+
 # Do you want failed tests to have their artifacts cleaned up?
 ART_TEST_RUN_TEST_ALWAYS_CLEAN ?= true
 
diff --git a/build/Android.executable.mk b/build/Android.executable.mk
index d887acd..86f445f 100644
--- a/build/Android.executable.mk
+++ b/build/Android.executable.mk
@@ -57,6 +57,7 @@
   LOCAL_SRC_FILES := $$(art_source)
   LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime $$(art_c_includes)
   LOCAL_SHARED_LIBRARIES += $$(art_shared_libraries)
+  LOCAL_WHOLE_STATIC_LIBRARIES += libsigchain
 
   ifeq ($$(art_ndebug_or_debug),ndebug)
     LOCAL_MODULE := $$(art_executable)
@@ -65,18 +66,25 @@
   endif
 
   LOCAL_CFLAGS := $(ART_EXECUTABLES_CFLAGS)
+  # Mac OS linker doesn't understand --export-dynamic/--version-script.
+  ifneq ($$(HOST_OS)-$$(art_target_or_host),darwin-host)
+    LOCAL_LDFLAGS := -Wl,--version-script,art/sigchainlib/version-script.txt -Wl,--export-dynamic
+  endif
+
   ifeq ($$(art_target_or_host),target)
   	$(call set-target-local-clang-vars)
   	$(call set-target-local-cflags-vars,$(6))
+    LOCAL_SHARED_LIBRARIES += libdl
   else # host
     LOCAL_CLANG := $(ART_HOST_CLANG)
+    LOCAL_LDLIBS := $(ART_HOST_LDLIBS)
     LOCAL_CFLAGS += $(ART_HOST_CFLAGS)
     ifeq ($$(art_ndebug_or_debug),debug)
       LOCAL_CFLAGS += $(ART_HOST_DEBUG_CFLAGS)
     else
       LOCAL_CFLAGS += $(ART_HOST_NON_DEBUG_CFLAGS)
     endif
-    LOCAL_LDLIBS += -lpthread
+    LOCAL_LDLIBS += -lpthread -ldl
   endif
 
   ifeq ($$(art_ndebug_or_debug),ndebug)
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index af43a3c..db7257a 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -141,7 +141,7 @@
   compiler/oat_test.cc \
   compiler/optimizing/codegen_test.cc \
   compiler/optimizing/dead_code_elimination_test.cc \
-  compiler/optimizing/constant_propagation_test.cc \
+  compiler/optimizing/constant_folding_test.cc \
   compiler/optimizing/dominator_test.cc \
   compiler/optimizing/find_loops_test.cc \
   compiler/optimizing/graph_checker_test.cc \
@@ -217,10 +217,7 @@
 LOCAL_C_INCLUDES := $(ART_C_INCLUDES) art/runtime art/compiler
 LOCAL_SHARED_LIBRARIES := libartd libartd-compiler
 LOCAL_STATIC_LIBRARIES := libcutils
-ifneq ($(WITHOUT_HOST_CLANG),true)
-  # GCC host compiled tests fail with this linked, presumably due to destructors that run.
-  LOCAL_STATIC_LIBRARIES += libgtest_libc++_host
-endif
+LOCAL_STATIC_LIBRARIES += libgtest_libc++_host
 LOCAL_LDLIBS += -ldl -lpthread
 LOCAL_MULTILIB := both
 LOCAL_CLANG := $(ART_HOST_CLANG)
@@ -264,7 +261,7 @@
 	  && (adb pull $(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@-$$$$PPID /tmp/ \
 	      && $$(call ART_TEST_PASSED,$$@)) \
 	  || $$(call ART_TEST_FAILED,$$@))
-	$(hide) rm /tmp/$$@-$$$$PPID
+	$(hide) rm -f /tmp/$$@-$$$$PPID
 
   ART_TEST_TARGET_GTEST$($(2)ART_PHONY_TEST_TARGET_SUFFIX)_RULES += $$(gtest_rule)
   ART_TEST_TARGET_GTEST_RULES += $$(gtest_rule)
@@ -287,7 +284,7 @@
 
 .PHONY: $$(gtest_rule)
 $$(gtest_rule): $$(gtest_exe) $$(ART_GTEST_$(1)_HOST_DEPS) $(foreach file,$(ART_GTEST_$(1)_DEX_DEPS),$(ART_TEST_HOST_GTEST_$(file)_DEX)) $$(gtest_deps)
-	$(hide) ($$(call ART_TEST_SKIP,$$@) && LD_PRELOAD=libsigchain$$(ART_HOST_SHLIB_EXTENSION) $$< && $$(call ART_TEST_PASSED,$$@)) \
+	$(hide) ($$(call ART_TEST_SKIP,$$@) && $$< && $$(call ART_TEST_PASSED,$$@)) \
 	  || $$(call ART_TEST_FAILED,$$@)
 
   ART_TEST_HOST_GTEST$$($(2)ART_PHONY_TEST_HOST_SUFFIX)_RULES += $$(gtest_rule)
@@ -338,6 +335,7 @@
   LOCAL_SRC_FILES := $$(art_gtest_filename)
   LOCAL_C_INCLUDES += $$(ART_C_INCLUDES) art/runtime $$(art_gtest_extra_c_includes)
   LOCAL_SHARED_LIBRARIES += libartd $$(art_gtest_extra_shared_libraries) libart-gtest
+  LOCAL_WHOLE_STATIC_LIBRARIES += libsigchain
 
   LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
   LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.gtest.mk
@@ -377,7 +375,7 @@
     LOCAL_CFLAGS += $$(ART_HOST_CFLAGS) $$(ART_HOST_DEBUG_CFLAGS)
     LOCAL_SHARED_LIBRARIES += libicuuc-host libicui18n-host libnativehelper libz-host
     LOCAL_STATIC_LIBRARIES += libcutils libvixl
-    LOCAL_LDLIBS += -lpthread -ldl
+    LOCAL_LDLIBS := $(ART_HOST_LDLIBS) -lpthread -ldl
     LOCAL_IS_HOST_MODULE := true
     LOCAL_MULTILIB := both
     LOCAL_MODULE_STEM_32 := $$(art_gtest_name)32
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index 844f58e..2becbb8 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -51,7 +51,7 @@
 endif
 
 define create-core-oat-target-rules
-$$($(1)TARGET_CORE_IMG_OUT): $$($(1)TARGET_CORE_DEX_FILES) $$(DEX2OAT_DEPENDENCY)
+$$($(1)TARGET_CORE_IMG_OUT): $$(TARGET_CORE_DEX_FILES) $$(DEX2OAT_DEPENDENCY)
 	@echo "target dex2oat: $$@ ($$?)"
 	@mkdir -p $$(dir $$@)
 	$$(hide) $$(DEX2OAT) $$(DEX2OAT_FLAGS) --runtime-arg -Xms$(DEX2OAT_XMS) --runtime-arg -Xmx$(DEX2OAT_XMX) \
diff --git a/compiler/Android.mk b/compiler/Android.mk
index edc5bd0..172c96c 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -88,9 +88,10 @@
 	optimizing/builder.cc \
 	optimizing/code_generator.cc \
 	optimizing/code_generator_arm.cc \
+	optimizing/code_generator_arm64.cc \
 	optimizing/code_generator_x86.cc \
 	optimizing/code_generator_x86_64.cc \
-	optimizing/constant_propagation.cc \
+	optimizing/constant_folding.cc \
 	optimizing/dead_code_elimination.cc \
 	optimizing/graph_checker.cc \
 	optimizing/graph_visualizer.cc \
@@ -98,6 +99,7 @@
 	optimizing/instruction_simplifier.cc \
 	optimizing/locations.cc \
 	optimizing/nodes.cc \
+	optimizing/optimization.cc \
 	optimizing/optimizing_compiler.cc \
 	optimizing/parallel_move_resolver.cc \
 	optimizing/prepare_for_register_allocation.cc \
@@ -223,6 +225,7 @@
   else # host
     LOCAL_CLANG := $(ART_HOST_CLANG)
     LOCAL_CFLAGS += $(ART_HOST_CFLAGS)
+    LOCAL_LDLIBS := $(ART_HOST_LDLIBS)
     ifeq ($$(art_ndebug_or_debug),debug)
       LOCAL_CFLAGS += $(ART_HOST_DEBUG_CFLAGS)
     else
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index e3eb9e9..359d6af 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -16,18 +16,12 @@
 
 #include "common_compiler_test.h"
 
-#if defined(__arm__)
-#include <sys/ucontext.h>
-#endif
-#include <fstream>
-
 #include "class_linker.h"
 #include "compiled_method.h"
 #include "dex/quick_compiler_callbacks.h"
 #include "dex/verification_results.h"
 #include "dex/quick/dex_file_to_method_inliner_map.h"
 #include "driver/compiler_driver.h"
-#include "entrypoints/entrypoint_utils.h"
 #include "interpreter/interpreter.h"
 #include "mirror/art_method.h"
 #include "mirror/dex_cache.h"
@@ -38,128 +32,9 @@
 
 namespace art {
 
-// Normally the ClassLinker supplies this.
-extern "C" void art_quick_generic_jni_trampoline(mirror::ArtMethod*);
-
-#if defined(__arm__)
-// A signal handler called when have an illegal instruction.  We record the fact in
-// a global boolean and then increment the PC in the signal context to return to
-// the next instruction.  We know the instruction is an sdiv (4 bytes long).
-static void baddivideinst(int signo, siginfo *si, void *data) {
-  UNUSED(signo);
-  UNUSED(si);
-  struct ucontext *uc = (struct ucontext *)data;
-  struct sigcontext *sc = &uc->uc_mcontext;
-  sc->arm_r0 = 0;     // set R0 to #0 to signal error
-  sc->arm_pc += 4;    // skip offending instruction
-}
-
-// This is in arch/arm/arm_sdiv.S.  It does the following:
-// mov r1,#1
-// sdiv r0,r1,r1
-// bx lr
-//
-// the result will be the value 1 if sdiv is supported.  If it is not supported
-// a SIGILL signal will be raised and the signal handler (baddivideinst) called.
-// The signal handler sets r0 to #0 and then increments pc beyond the failed instruction.
-// Thus if the instruction is not supported, the result of this function will be #0
-
-extern "C" bool CheckForARMSDIVInstruction();
-
-static InstructionSetFeatures GuessInstructionFeatures() {
-  InstructionSetFeatures f;
-
-  // Uncomment this for processing of /proc/cpuinfo.
-  if (false) {
-    // Look in /proc/cpuinfo for features we need.  Only use this when we can guarantee that
-    // the kernel puts the appropriate feature flags in here.  Sometimes it doesn't.
-    std::ifstream in("/proc/cpuinfo");
-    if (in) {
-      while (!in.eof()) {
-        std::string line;
-        std::getline(in, line);
-        if (!in.eof()) {
-          if (line.find("Features") != std::string::npos) {
-            if (line.find("idivt") != std::string::npos) {
-              f.SetHasDivideInstruction(true);
-            }
-          }
-        }
-        in.close();
-      }
-    } else {
-      LOG(INFO) << "Failed to open /proc/cpuinfo";
-    }
-  }
-
-  // See if have a sdiv instruction.  Register a signal handler and try to execute
-  // an sdiv instruction.  If we get a SIGILL then it's not supported.  We can't use
-  // the /proc/cpuinfo method for this because Krait devices don't always put the idivt
-  // feature in the list.
-  struct sigaction sa, osa;
-  sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
-  sa.sa_sigaction = baddivideinst;
-  sigaction(SIGILL, &sa, &osa);
-
-  if (CheckForARMSDIVInstruction()) {
-    f.SetHasDivideInstruction(true);
-  }
-
-  // Restore the signal handler.
-  sigaction(SIGILL, &osa, nullptr);
-
-  // Other feature guesses in here.
-  return f;
-}
-#endif
-
-// Given a set of instruction features from the build, parse it.  The
-// input 'str' is a comma separated list of feature names.  Parse it and
-// return the InstructionSetFeatures object.
-static InstructionSetFeatures ParseFeatureList(std::string str) {
-  InstructionSetFeatures result;
-  typedef std::vector<std::string> FeatureList;
-  FeatureList features;
-  Split(str, ',', features);
-  for (FeatureList::iterator i = features.begin(); i != features.end(); i++) {
-    std::string feature = Trim(*i);
-    if (feature == "default") {
-      // Nothing to do.
-    } else if (feature == "div") {
-      // Supports divide instruction.
-      result.SetHasDivideInstruction(true);
-    } else if (feature == "nodiv") {
-      // Turn off support for divide instruction.
-      result.SetHasDivideInstruction(false);
-    } else {
-      LOG(FATAL) << "Unknown instruction set feature: '" << feature << "'";
-    }
-  }
-  // Others...
-  return result;
-}
-
 CommonCompilerTest::CommonCompilerTest() {}
 CommonCompilerTest::~CommonCompilerTest() {}
 
-OatFile::OatMethod CommonCompilerTest::CreateOatMethod(const void* code, const uint8_t* gc_map) {
-  CHECK(code != nullptr);
-  const uint8_t* base;
-  uint32_t code_offset, gc_map_offset;
-  if (gc_map == nullptr) {
-    base = reinterpret_cast<const uint8_t*>(code);  // Base of data points at code.
-    base -= sizeof(void*);  // Move backward so that code_offset != 0.
-    code_offset = sizeof(void*);
-    gc_map_offset = 0;
-  } else {
-    // TODO: 64bit support.
-    base = nullptr;  // Base of data in oat file, ie 0.
-    code_offset = PointerToLowMemUInt32(code);
-    gc_map_offset = PointerToLowMemUInt32(gc_map);
-  }
-  return OatFile::OatMethod(base, code_offset, gc_map_offset);
-}
-
 void CommonCompilerTest::MakeExecutable(mirror::ArtMethod* method) {
   CHECK(method != nullptr);
 
@@ -174,7 +49,8 @@
   if (compiled_method != nullptr) {
     const std::vector<uint8_t>* code = compiled_method->GetQuickCode();
     const void* code_ptr;
-    if (code != nullptr) {
+    bool is_portable = (code == nullptr);
+    if (!is_portable) {
       uint32_t code_size = code->size();
       CHECK_NE(0u, code_size);
       const std::vector<uint8_t>& vmap_table = compiled_method->GetVmapTable();
@@ -210,33 +86,11 @@
     const void* method_code = CompiledMethod::CodePointer(code_ptr,
                                                           compiled_method->GetInstructionSet());
     LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code;
-    OatFile::OatMethod oat_method = CreateOatMethod(method_code, nullptr);
-    oat_method.LinkMethod(method);
-    method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
+    class_linker_->SetEntryPointsToCompiledCode(method, method_code, is_portable);
   } else {
     // No code? You must mean to go into the interpreter.
     // Or the generic JNI...
-    if (!method->IsNative()) {
-      const void* method_code = kUsePortableCompiler ? GetPortableToInterpreterBridge()
-          : GetQuickToInterpreterBridge();
-      OatFile::OatMethod oat_method = CreateOatMethod(method_code, nullptr);
-      oat_method.LinkMethod(method);
-      method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge);
-    } else {
-      const void* method_code = reinterpret_cast<void*>(art_quick_generic_jni_trampoline);
-
-      OatFile::OatMethod oat_method = CreateOatMethod(method_code, nullptr);
-      oat_method.LinkMethod(method);
-      method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
-    }
-  }
-  // Create bridges to transition between different kinds of compiled bridge.
-  if (method->GetEntryPointFromPortableCompiledCode() == nullptr) {
-    method->SetEntryPointFromPortableCompiledCode(GetPortableToQuickBridge());
-  } else {
-    CHECK(method->GetEntryPointFromQuickCompiledCode() == nullptr);
-    method->SetEntryPointFromQuickCompiledCode(GetQuickToPortableBridge());
-    method->SetIsPortableCompiled();
+    class_linker_->SetEntryPointsToInterpreter(method);
   }
 }
 
@@ -282,19 +136,9 @@
   {
     ScopedObjectAccess soa(Thread::Current());
 
-    InstructionSet instruction_set = kRuntimeISA;
-
+    const InstructionSet instruction_set = kRuntimeISA;
     // Take the default set of instruction features from the build.
-    InstructionSetFeatures instruction_set_features =
-        ParseFeatureList(Runtime::GetDefaultInstructionSetFeatures());
-
-#if defined(__arm__)
-    InstructionSetFeatures runtime_features = GuessInstructionFeatures();
-
-    // for ARM, do a runtime check to make sure that the features we are passed from
-    // the build match the features we actually determine at runtime.
-    ASSERT_LE(instruction_set_features, runtime_features);
-#endif
+    instruction_set_features_.reset(InstructionSetFeatures::FromCppDefines());
 
     runtime_->SetInstructionSet(instruction_set);
     for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
@@ -306,16 +150,15 @@
     }
 
     // TODO: make selectable
-    Compiler::Kind compiler_kind
-    = (kUsePortableCompiler) ? Compiler::kPortable : Compiler::kQuick;
+    Compiler::Kind compiler_kind = kUsePortableCompiler ? Compiler::kPortable : Compiler::kQuick;
     timer_.reset(new CumulativeLogger("Compilation times"));
     compiler_driver_.reset(new CompilerDriver(compiler_options_.get(),
                                               verification_results_.get(),
                                               method_inliner_map_.get(),
                                               compiler_kind, instruction_set,
-                                              instruction_set_features,
+                                              instruction_set_features_.get(),
                                               true, new std::set<std::string>,
-                                              2, true, true, timer_.get()));
+                                              2, true, true, timer_.get(), ""));
   }
   // We typically don't generate an image in unit tests, disable this optimization by default.
   compiler_driver_->SetSupportBootImageFixup(false);
@@ -397,6 +240,7 @@
   // Reserve where the image will be loaded up front so that other parts of test set up don't
   // accidentally end up colliding with the fixed memory address when we need to load the image.
   std::string error_msg;
+  MemMap::Init();
   image_reservation_.reset(MemMap::MapAnonymous("image reservation",
                                                 reinterpret_cast<uint8_t*>(ART_BASE_ADDRESS),
                                                 (size_t)100 * 1024 * 1024,  // 100MB
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index df06b71..20b750c 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -81,6 +81,8 @@
   std::unique_ptr<CompilerCallbacks> callbacks_;
   std::unique_ptr<CompilerDriver> compiler_driver_;
   std::unique_ptr<CumulativeLogger> timer_;
+  std::unique_ptr<const InstructionSetFeatures> instruction_set_features_;
+
 
  private:
   std::unique_ptr<MemMap> image_reservation_;
diff --git a/compiler/dex/bb_optimizations.h b/compiler/dex/bb_optimizations.h
index fce23bc..764a4cf 100644
--- a/compiler/dex/bb_optimizations.h
+++ b/compiler/dex/bb_optimizations.h
@@ -143,7 +143,7 @@
 class NullCheckElimination : public PassME {
  public:
   NullCheckElimination()
-    : PassME("NCE", kRepeatingTopologicalSortTraversal, "3_post_nce_cfg") {
+    : PassME("NCE", kRepeatingPreOrderDFSTraversal, "3_post_nce_cfg") {
   }
 
   bool Gate(const PassDataHolder* data) const {
@@ -178,7 +178,7 @@
 class TypeInference : public PassME {
  public:
   TypeInference()
-    : PassME("TypeInference", kRepeatingTopologicalSortTraversal, "4_post_type_cfg") {
+    : PassME("TypeInference", kRepeatingPreOrderDFSTraversal, "4_post_type_cfg") {
   }
 
   bool Worker(PassDataHolder* data) const {
@@ -195,7 +195,7 @@
 class ClassInitCheckElimination : public PassME {
  public:
   ClassInitCheckElimination()
-    : PassME("ClInitCheckElimination", kLoopRepeatingTopologicalSortTraversal) {
+    : PassME("ClInitCheckElimination", kRepeatingPreOrderDFSTraversal) {
   }
 
   bool Gate(const PassDataHolder* data) const {
@@ -271,7 +271,8 @@
     DCHECK(data != nullptr);
     CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit;
     DCHECK(c_unit != nullptr);
-    return ((c_unit->disable_opt & (1 << kSuppressExceptionEdges)) != 0);
+    return c_unit->mir_graph->HasTryCatchBlocks() ||
+        ((c_unit->disable_opt & (1 << kSuppressExceptionEdges)) != 0);
   }
 
   bool Worker(PassDataHolder* data) const;
diff --git a/compiler/dex/compiler_enums.h b/compiler/dex/compiler_enums.h
index e4003bf..78da420 100644
--- a/compiler/dex/compiler_enums.h
+++ b/compiler/dex/compiler_enums.h
@@ -311,7 +311,8 @@
   kMIRCallee,                         // Instruction is inlined from callee.
   kMIRIgnoreSuspendCheck,
   kMIRDup,
-  kMIRMark,                           // Temporary node mark.
+  kMIRMark,                           // Temporary node mark can be used by
+                                      // opt passes for their private needs.
   kMIRStoreNonTemporal,
   kMIRLastMIRFlag,
 };
diff --git a/compiler/dex/compiler_ir.cc b/compiler/dex/compiler_ir.cc
index 909c995..a2b3fe4 100644
--- a/compiler/dex/compiler_ir.cc
+++ b/compiler/dex/compiler_ir.cc
@@ -16,6 +16,7 @@
 
 #include "compiler_ir.h"
 
+#include "base/dumpable.h"
 #include "backend.h"
 #include "frontend.h"
 #include "mir_graph.h"
diff --git a/compiler/dex/compiler_ir.h b/compiler/dex/compiler_ir.h
index 37e3a7a..34585c1 100644
--- a/compiler/dex/compiler_ir.h
+++ b/compiler/dex/compiler_ir.h
@@ -68,7 +68,7 @@
   InstructionSet instruction_set;
   bool target64;
 
-  InstructionSetFeatures GetInstructionSetFeatures() {
+  const InstructionSetFeatures* GetInstructionSetFeatures() {
     return compiler_driver->GetInstructionSetFeatures();
   }
 
diff --git a/compiler/dex/dataflow_iterator-inl.h b/compiler/dex/dataflow_iterator-inl.h
index 89f2b5c..6e25db6 100644
--- a/compiler/dex/dataflow_iterator-inl.h
+++ b/compiler/dex/dataflow_iterator-inl.h
@@ -115,6 +115,30 @@
   return res;
 }
 
+inline BasicBlock* TopologicalSortIterator::Next(bool had_change) {
+  // Update changed: if had_changed is true, we remember it for the whole iteration.
+  changed_ |= had_change;
+
+  while (loop_head_stack_->size() != 0u &&
+      (*loop_ends_)[loop_head_stack_->back().first] == idx_) {
+    loop_head_stack_->pop_back();
+  }
+
+  if (idx_ == end_idx_) {
+    return nullptr;
+  }
+
+  // Get next block and return it.
+  BasicBlockId idx = idx_;
+  idx_ += 1;
+  BasicBlock* bb = mir_graph_->GetBasicBlock((*block_id_list_)[idx]);
+  DCHECK(bb != nullptr);
+  if ((*loop_ends_)[idx] != 0u) {
+    loop_head_stack_->push_back(std::make_pair(idx, false));  // Not recalculating.
+  }
+  return bb;
+}
+
 inline BasicBlock* LoopRepeatingTopologicalSortIterator::Next(bool had_change) {
   if (idx_ != 0) {
     // Mark last processed block visited.
diff --git a/compiler/dex/dataflow_iterator.h b/compiler/dex/dataflow_iterator.h
index 188f1d9..9f17a3e 100644
--- a/compiler/dex/dataflow_iterator.h
+++ b/compiler/dex/dataflow_iterator.h
@@ -333,7 +333,9 @@
        * @param mir_graph The MIRGraph considered.
        */
       explicit TopologicalSortIterator(MIRGraph* mir_graph)
-          : DataflowIterator(mir_graph, 0, mir_graph->GetTopologicalSortOrder().size()) {
+          : DataflowIterator(mir_graph, 0, mir_graph->GetTopologicalSortOrder().size()),
+            loop_ends_(&mir_graph->GetTopologicalSortOrderLoopEnds()),
+            loop_head_stack_(mir_graph_->GetTopologicalSortOrderLoopHeadStack()) {
         // Extra setup for TopologicalSortIterator.
         idx_ = start_idx_;
         block_id_list_ = &mir_graph->GetTopologicalSortOrder();
@@ -344,44 +346,11 @@
        * @param had_change did the user of the iteration change the previous BasicBlock.
        * @return the next BasicBlock following the iteration order, 0 if finished.
        */
-      virtual BasicBlock* Next(bool had_change = false) {
-        // Update changed: if had_changed is true, we remember it for the whole iteration.
-        changed_ |= had_change;
+      virtual BasicBlock* Next(bool had_change = false) OVERRIDE;
 
-        return ForwardSingleNext();
-      }
-  };
-
-  /**
-   * @class RepeatingTopologicalSortIterator
-   * @brief Used to perform a Topological Sort Iteration of a MIRGraph.
-   * @details If there is a change during an iteration, the iteration starts over at the end of the
-   *          iteration.
-   */
-  class RepeatingTopologicalSortIterator : public DataflowIterator {
-    public:
-     /**
-      * @brief The constructor, using all of the reachable blocks of the MIRGraph.
-      * @param mir_graph The MIRGraph considered.
-      */
-     explicit RepeatingTopologicalSortIterator(MIRGraph* mir_graph)
-         : DataflowIterator(mir_graph, 0, mir_graph->GetTopologicalSortOrder().size()) {
-       // Extra setup for RepeatingTopologicalSortIterator.
-       idx_ = start_idx_;
-       block_id_list_ = &mir_graph->GetTopologicalSortOrder();
-     }
-
-     /**
-      * @brief Get the next BasicBlock depending on iteration order.
-      * @param had_change did the user of the iteration change the previous BasicBlock.
-      * @return the next BasicBlock following the iteration order, 0 if finished.
-      */
-     virtual BasicBlock* Next(bool had_change = false) {
-       // Update changed: if had_changed is true, we remember it for the whole iteration.
-       changed_ |= had_change;
-
-       return ForwardRepeatNext();
-     }
+    private:
+     const ArenaVector<BasicBlockId>* const loop_ends_;
+     ArenaVector<std::pair<uint16_t, bool>>* const loop_head_stack_;
   };
 
   /**
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index 07f3033..3dc5655 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -19,6 +19,7 @@
 #include <cstdint>
 
 #include "backend.h"
+#include "base/dumpable.h"
 #include "compiler.h"
 #include "compiler_internals.h"
 #include "driver/compiler_driver.h"
@@ -41,6 +42,7 @@
   // (1 << kNullCheckElimination) |
   // (1 << kClassInitCheckElimination) |
   // (1 << kGlobalValueNumbering) |
+  // (1 << kLocalValueNumbering) |
   // (1 << kPromoteRegs) |
   // (1 << kTrackLiveTemps) |
   // (1 << kSafeOptimizations) |
@@ -133,15 +135,8 @@
         (cu.enable_debug & (1 << kDebugVerbose));
   }
 
-  if (gVerboseMethods.size() != 0) {
-    cu.verbose = false;
-    for (size_t i = 0; i < gVerboseMethods.size(); ++i) {
-      if (PrettyMethod(method_idx, dex_file).find(gVerboseMethods[i])
-          != std::string::npos) {
-        cu.verbose = true;
-        break;
-      }
-    }
+  if (driver.GetCompilerOptions().HasVerboseMethods()) {
+    cu.verbose = driver.GetCompilerOptions().IsVerboseMethod(PrettyMethod(method_idx, dex_file));
   }
 
   if (cu.verbose) {
diff --git a/compiler/dex/frontend.h b/compiler/dex/frontend.h
index 51b6d68..bed3b97 100644
--- a/compiler/dex/frontend.h
+++ b/compiler/dex/frontend.h
@@ -41,6 +41,7 @@
   kNullCheckElimination,
   kClassInitCheckElimination,
   kGlobalValueNumbering,
+  kLocalValueNumbering,
   kPromoteRegs,
   kTrackLiveTemps,
   kSafeOptimizations,
diff --git a/compiler/dex/global_value_numbering.cc b/compiler/dex/global_value_numbering.cc
index af57529..f0f7a70 100644
--- a/compiler/dex/global_value_numbering.cc
+++ b/compiler/dex/global_value_numbering.cc
@@ -20,14 +20,16 @@
 
 namespace art {
 
-GlobalValueNumbering::GlobalValueNumbering(CompilationUnit* cu, ScopedArenaAllocator* allocator)
+GlobalValueNumbering::GlobalValueNumbering(CompilationUnit* cu, ScopedArenaAllocator* allocator,
+                                           Mode mode)
     : cu_(cu),
       mir_graph_(cu->mir_graph.get()),
       allocator_(allocator),
       bbs_processed_(0u),
       max_bbs_to_process_(kMaxBbsToProcessMultiplyFactor * mir_graph_->GetNumReachableBlocks()),
       last_value_(0u),
-      modifications_allowed_(false),
+      modifications_allowed_(true),
+      mode_(mode),
       global_value_map_(std::less<uint64_t>(), allocator->Adapter()),
       field_index_map_(FieldReferenceComparator(), allocator->Adapter()),
       field_index_reverse_map_(allocator->Adapter()),
@@ -48,19 +50,19 @@
   if (UNLIKELY(!Good())) {
     return nullptr;
   }
-  if (UNLIKELY(bb->data_flow_info == nullptr)) {
-    return nullptr;
-  }
-  if (UNLIKELY(bb->block_type == kExitBlock)) {
+  if (bb->block_type != kDalvikByteCode && bb->block_type != kEntryBlock) {
     DCHECK(bb->first_mir_insn == nullptr);
     return nullptr;
   }
-  if (UNLIKELY(bbs_processed_ == max_bbs_to_process_)) {
+  if (mode_ == kModeGvn && UNLIKELY(bbs_processed_ == max_bbs_to_process_)) {
     // If we're still trying to converge, stop now. Otherwise, proceed to apply optimizations.
-    if (!modifications_allowed_) {
-      last_value_ = kNoValue;  // Make bad.
-      return nullptr;
-    }
+    last_value_ = kNoValue;  // Make bad.
+    return nullptr;
+  }
+  if (mode_ == kModeGvnPostProcessing &&
+    mir_graph_->GetTopologicalSortOrderLoopHeadStack()->empty()) {
+    // Modifications outside loops are performed during the main phase.
+    return nullptr;
   }
   if (allocator == nullptr) {
     allocator = allocator_;
@@ -74,6 +76,7 @@
       uint16_t value_name = work_lvn_->GetSRegValueName(this_reg);
       work_lvn_->SetValueNameNullChecked(value_name);
     }
+    DCHECK(bb->first_mir_insn == nullptr);  // modifications_allowed_ is irrelevant.
   } else {
     // To avoid repeated allocation on the ArenaStack, reuse a single vector kept as a member.
     DCHECK(merge_lvns_.empty());
@@ -83,19 +86,18 @@
     // topological order, or we're recalculating a loop head and need to merge all incoming
     // LVNs. When we're not at a loop head (including having an empty loop head stack) all
     // predecessors should be preceding blocks and we shall merge all of them anyway.
-    //
-    // If we're running the modification phase of the full GVN, the loop head stack will be
-    // empty and we need to merge all incoming LVNs. If we're running just a simple LVN,
-    // the loop head stack will also be empty and there will be nothing to merge anyway.
     bool use_all_predecessors = true;
     uint16_t loop_head_idx = 0u;  // Used only if !use_all_predecessors.
-    if (mir_graph_->GetTopologicalSortOrderLoopHeadStack()->size() != 0) {
+    if (mode_ == kModeGvn && mir_graph_->GetTopologicalSortOrderLoopHeadStack()->size() != 0) {
       // Full GVN inside a loop, see if we're at the loop head for the first time.
+      modifications_allowed_ = false;
       auto top = mir_graph_->GetTopologicalSortOrderLoopHeadStack()->back();
       loop_head_idx = top.first;
       bool recalculating = top.second;
       use_all_predecessors = recalculating ||
           loop_head_idx != mir_graph_->GetTopologicalSortOrderIndexes()[bb->id];
+    } else {
+      modifications_allowed_ = true;
     }
     for (BasicBlockId pred_id : bb->predecessors) {
       DCHECK_NE(pred_id, NullBasicBlockId);
diff --git a/compiler/dex/global_value_numbering.h b/compiler/dex/global_value_numbering.h
index 27183bf..df554cd 100644
--- a/compiler/dex/global_value_numbering.h
+++ b/compiler/dex/global_value_numbering.h
@@ -28,7 +28,18 @@
 
 class GlobalValueNumbering {
  public:
-  GlobalValueNumbering(CompilationUnit* cu, ScopedArenaAllocator* allocator);
+  enum Mode {
+    kModeGvn,
+    kModeGvnPostProcessing,
+    kModeLvn
+  };
+
+  static bool Skip(CompilationUnit* cu) {
+    return (cu->disable_opt & (1u << kGlobalValueNumbering)) != 0u ||
+        cu->mir_graph->GetMaxNestedLoops() > kMaxAllowedNestedLoops;
+  }
+
+  GlobalValueNumbering(CompilationUnit* cu, ScopedArenaAllocator* allocator, Mode mode);
   ~GlobalValueNumbering();
 
   // Prepare LVN for the basic block.
@@ -44,13 +55,13 @@
   }
 
   // Allow modifications.
-  void AllowModifications() {
+  void StartPostProcessing() {
     DCHECK(Good());
-    modifications_allowed_ = true;
+    DCHECK_EQ(mode_, kModeGvn);
+    mode_ = kModeGvnPostProcessing;
   }
 
   bool CanModify() const {
-    // TODO: DCHECK(Good()), see AllowModifications() and NewValueName().
     return modifications_allowed_ && Good();
   }
 
@@ -67,8 +78,7 @@
 
   // Allocate a new value name.
   uint16_t NewValueName() {
-    // TODO: No new values should be needed once we allow modifications.
-    // DCHECK(!modifications_allowed_);
+    DCHECK_NE(mode_, kModeGvnPostProcessing);
     ++last_value_;
     return last_value_;
   }
@@ -208,6 +218,9 @@
   MIRGraph* mir_graph_;
   ScopedArenaAllocator* const allocator_;
 
+  // The maximum number of nested loops that we accept for GVN.
+  static constexpr size_t kMaxAllowedNestedLoops = 6u;
+
   // The number of BBs that we need to process grows exponentially with the number
   // of nested loops. Don't allow excessive processing for too many nested loops or
   // otherwise expensive methods.
@@ -225,6 +238,9 @@
   // LVN once for each BasicBlock.
   bool modifications_allowed_;
 
+  // Specifies the mode of operation.
+  Mode mode_;
+
   ValueMap global_value_map_;
   FieldIndexMap field_index_map_;
   ScopedArenaVector<const FieldIndexMap::value_type*> field_index_reverse_map_;
diff --git a/compiler/dex/global_value_numbering_test.cc b/compiler/dex/global_value_numbering_test.cc
index 1d9920d..82a11a5 100644
--- a/compiler/dex/global_value_numbering_test.cc
+++ b/compiler/dex/global_value_numbering_test.cc
@@ -284,8 +284,8 @@
     cu_.mir_graph->ComputeTopologicalSortOrder();
     cu_.mir_graph->SSATransformationEnd();
     ASSERT_TRUE(gvn_ == nullptr);
-    gvn_.reset(new (allocator_.get()) GlobalValueNumbering(&cu_, allocator_.get()));
-    ASSERT_FALSE(gvn_->CanModify());
+    gvn_.reset(new (allocator_.get()) GlobalValueNumbering(&cu_, allocator_.get(),
+                                                           GlobalValueNumbering::kModeGvn));
     value_names_.resize(mir_count_, 0xffffu);
     IteratorType iterator(cu_.mir_graph.get());
     bool change = false;
@@ -304,8 +304,7 @@
   void PerformGVNCodeModifications() {
     ASSERT_TRUE(gvn_ != nullptr);
     ASSERT_TRUE(gvn_->Good());
-    ASSERT_FALSE(gvn_->CanModify());
-    gvn_->AllowModifications();
+    gvn_->StartPostProcessing();
     TopologicalSortIterator iterator(cu_.mir_graph.get());
     for (BasicBlock* bb = iterator.Next(); bb != nullptr; bb = iterator.Next()) {
       LocalValueNumbering* lvn = gvn_->PrepareBasicBlock(bb);
diff --git a/compiler/dex/local_value_numbering.cc b/compiler/dex/local_value_numbering.cc
index eb98916..8b7ae20 100644
--- a/compiler/dex/local_value_numbering.cc
+++ b/compiler/dex/local_value_numbering.cc
@@ -1413,8 +1413,8 @@
     case Instruction::MONITOR_EXIT:
       HandleNullCheck(mir, GetOperandValue(mir->ssa_rep->uses[0]));
       // If we're running GVN and CanModify(), uneliminated null check indicates bytecode error.
-      if ((gvn_->GetCompilationUnit()->disable_opt & (1u << kGlobalValueNumbering)) == 0u &&
-          gvn_->CanModify() && (mir->optimization_flags & MIR_IGNORE_NULL_CHECK) == 0) {
+      if ((mir->optimization_flags & MIR_IGNORE_NULL_CHECK) == 0 &&
+          gvn_->work_lvn_ != nullptr && gvn_->CanModify()) {
         LOG(WARNING) << "Bytecode error: MONITOR_EXIT is still null checked at 0x" << std::hex
             << mir->offset << " in " << PrettyMethod(gvn_->cu_->method_idx, *gvn_->cu_->dex_file);
       }
@@ -1448,6 +1448,10 @@
       }
       break;
 
+    case kMirOpNullCheck:
+      HandleNullCheck(mir, GetOperandValue(mir->ssa_rep->uses[0]));
+      break;
+
     case Instruction::INVOKE_DIRECT:
     case Instruction::INVOKE_DIRECT_RANGE:
     case Instruction::INVOKE_VIRTUAL:
diff --git a/compiler/dex/local_value_numbering_test.cc b/compiler/dex/local_value_numbering_test.cc
index 067bea2..33d6c14 100644
--- a/compiler/dex/local_value_numbering_test.cc
+++ b/compiler/dex/local_value_numbering_test.cc
@@ -195,9 +195,9 @@
         value_names_() {
     cu_.mir_graph.reset(new MIRGraph(&cu_, &cu_.arena));
     allocator_.reset(ScopedArenaAllocator::Create(&cu_.arena_stack));
-    gvn_.reset(new (allocator_.get()) GlobalValueNumbering(&cu_, allocator_.get()));
+    gvn_.reset(new (allocator_.get()) GlobalValueNumbering(&cu_, allocator_.get(),
+                                                           GlobalValueNumbering::kModeLvn));
     lvn_.reset(new (allocator_.get()) LocalValueNumbering(gvn_.get(), 0u, allocator_.get()));
-    gvn_->AllowModifications();
   }
 
   ArenaPool pool_;
diff --git a/compiler/dex/mir_dataflow.cc b/compiler/dex/mir_dataflow.cc
index 51b6709..0a6924c 100644
--- a/compiler/dex/mir_dataflow.cc
+++ b/compiler/dex/mir_dataflow.cc
@@ -118,10 +118,10 @@
   DF_DA | DF_REF_A | DF_NON_NULL_DST,
 
   // 1D MONITOR_ENTER vAA
-  DF_UA | DF_NULL_CHK_0 | DF_REF_A,
+  DF_UA | DF_NULL_CHK_A | DF_REF_A,
 
   // 1E MONITOR_EXIT vAA
-  DF_UA | DF_NULL_CHK_0 | DF_REF_A,
+  DF_UA | DF_NULL_CHK_A | DF_REF_A,
 
   // 1F CHK_CAST vAA, type@BBBB
   DF_UA | DF_REF_A | DF_UMS,
@@ -130,7 +130,7 @@
   DF_DA | DF_UB | DF_CORE_A | DF_REF_B | DF_UMS,
 
   // 21 ARRAY_LENGTH vA, vB
-  DF_DA | DF_UB | DF_NULL_CHK_0 | DF_CORE_A | DF_REF_B,
+  DF_DA | DF_UB | DF_NULL_CHK_B | DF_CORE_A | DF_REF_B,
 
   // 22 NEW_INSTANCE vAA, type@BBBB
   DF_DA | DF_NON_NULL_DST | DF_REF_A | DF_UMS,
@@ -235,88 +235,88 @@
   DF_NOP,
 
   // 44 AGET vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C | DF_LVN,
+  DF_DA | DF_UB | DF_UC | DF_NULL_CHK_B | DF_RANGE_CHK_C | DF_REF_B | DF_CORE_C | DF_LVN,
 
   // 45 AGET_WIDE vAA, vBB, vCC
-  DF_DA | DF_A_WIDE | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C | DF_LVN,
+  DF_DA | DF_A_WIDE | DF_UB | DF_UC | DF_NULL_CHK_B | DF_RANGE_CHK_C | DF_REF_B | DF_CORE_C | DF_LVN,
 
   // 46 AGET_OBJECT vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_A | DF_REF_B | DF_CORE_C | DF_LVN,
+  DF_DA | DF_UB | DF_UC | DF_NULL_CHK_B | DF_RANGE_CHK_C | DF_REF_A | DF_REF_B | DF_CORE_C | DF_LVN,
 
   // 47 AGET_BOOLEAN vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C | DF_LVN,
+  DF_DA | DF_UB | DF_UC | DF_NULL_CHK_B | DF_RANGE_CHK_C | DF_REF_B | DF_CORE_C | DF_LVN,
 
   // 48 AGET_BYTE vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C | DF_LVN,
+  DF_DA | DF_UB | DF_UC | DF_NULL_CHK_B | DF_RANGE_CHK_C | DF_REF_B | DF_CORE_C | DF_LVN,
 
   // 49 AGET_CHAR vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C | DF_LVN,
+  DF_DA | DF_UB | DF_UC | DF_NULL_CHK_B | DF_RANGE_CHK_C | DF_REF_B | DF_CORE_C | DF_LVN,
 
   // 4A AGET_SHORT vAA, vBB, vCC
-  DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C | DF_LVN,
+  DF_DA | DF_UB | DF_UC | DF_NULL_CHK_B | DF_RANGE_CHK_C | DF_REF_B | DF_CORE_C | DF_LVN,
 
   // 4B APUT vAA, vBB, vCC
-  DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_B | DF_CORE_C | DF_LVN,
+  DF_UA | DF_UB | DF_UC | DF_NULL_CHK_B | DF_RANGE_CHK_C | DF_REF_B | DF_CORE_C | DF_LVN,
 
   // 4C APUT_WIDE vAA, vBB, vCC
-  DF_UA | DF_A_WIDE | DF_UB | DF_UC | DF_NULL_CHK_2 | DF_RANGE_CHK_3 | DF_REF_B | DF_CORE_C | DF_LVN,
+  DF_UA | DF_A_WIDE | DF_UB | DF_UC | DF_NULL_CHK_B | DF_RANGE_CHK_C | DF_REF_B | DF_CORE_C | DF_LVN,
 
   // 4D APUT_OBJECT vAA, vBB, vCC
-  DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_A | DF_REF_B | DF_CORE_C | DF_LVN,
+  DF_UA | DF_UB | DF_UC | DF_NULL_CHK_B | DF_RANGE_CHK_C | DF_REF_A | DF_REF_B | DF_CORE_C | DF_LVN,
 
   // 4E APUT_BOOLEAN vAA, vBB, vCC
-  DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_B | DF_CORE_C | DF_LVN,
+  DF_UA | DF_UB | DF_UC | DF_NULL_CHK_B | DF_RANGE_CHK_C | DF_REF_B | DF_CORE_C | DF_LVN,
 
   // 4F APUT_BYTE vAA, vBB, vCC
-  DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_B | DF_CORE_C | DF_LVN,
+  DF_UA | DF_UB | DF_UC | DF_NULL_CHK_B | DF_RANGE_CHK_C | DF_REF_B | DF_CORE_C | DF_LVN,
 
   // 50 APUT_CHAR vAA, vBB, vCC
-  DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_B | DF_CORE_C | DF_LVN,
+  DF_UA | DF_UB | DF_UC | DF_NULL_CHK_B | DF_RANGE_CHK_C | DF_REF_B | DF_CORE_C | DF_LVN,
 
   // 51 APUT_SHORT vAA, vBB, vCC
-  DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_REF_B | DF_CORE_C | DF_LVN,
+  DF_UA | DF_UB | DF_UC | DF_NULL_CHK_B | DF_RANGE_CHK_C | DF_REF_B | DF_CORE_C | DF_LVN,
 
   // 52 IGET vA, vB, field@CCCC
-  DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B | DF_IFIELD | DF_LVN,
+  DF_DA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
 
   // 53 IGET_WIDE vA, vB, field@CCCC
-  DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_0 | DF_REF_B | DF_IFIELD | DF_LVN,
+  DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
 
   // 54 IGET_OBJECT vA, vB, field@CCCC
-  DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_A | DF_REF_B | DF_IFIELD | DF_LVN,
+  DF_DA | DF_UB | DF_NULL_CHK_B | DF_REF_A | DF_REF_B | DF_IFIELD | DF_LVN,
 
   // 55 IGET_BOOLEAN vA, vB, field@CCCC
-  DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B | DF_IFIELD | DF_LVN,
+  DF_DA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
 
   // 56 IGET_BYTE vA, vB, field@CCCC
-  DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B | DF_IFIELD | DF_LVN,
+  DF_DA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
 
   // 57 IGET_CHAR vA, vB, field@CCCC
-  DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B | DF_IFIELD | DF_LVN,
+  DF_DA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
 
   // 58 IGET_SHORT vA, vB, field@CCCC
-  DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B | DF_IFIELD | DF_LVN,
+  DF_DA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
 
   // 59 IPUT vA, vB, field@CCCC
-  DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B | DF_IFIELD | DF_LVN,
+  DF_UA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
 
   // 5A IPUT_WIDE vA, vB, field@CCCC
-  DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_2 | DF_REF_B | DF_IFIELD | DF_LVN,
+  DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
 
   // 5B IPUT_OBJECT vA, vB, field@CCCC
-  DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_A | DF_REF_B | DF_IFIELD | DF_LVN,
+  DF_UA | DF_UB | DF_NULL_CHK_B | DF_REF_A | DF_REF_B | DF_IFIELD | DF_LVN,
 
   // 5C IPUT_BOOLEAN vA, vB, field@CCCC
-  DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B | DF_IFIELD | DF_LVN,
+  DF_UA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
 
   // 5D IPUT_BYTE vA, vB, field@CCCC
-  DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B | DF_IFIELD | DF_LVN,
+  DF_UA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
 
   // 5E IPUT_CHAR vA, vB, field@CCCC
-  DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B | DF_IFIELD | DF_LVN,
+  DF_UA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
 
   // 5F IPUT_SHORT vA, vB, field@CCCC
-  DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B | DF_IFIELD | DF_LVN,
+  DF_UA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
 
   // 60 SGET vAA, field@BBBB
   DF_DA | DF_SFIELD | DF_UMS,
@@ -712,10 +712,10 @@
   DF_DA | DF_UB | DF_CORE_A | DF_CORE_B,
 
   // E3 IGET_VOLATILE
-  DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_B | DF_IFIELD | DF_LVN,
+  DF_DA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
 
   // E4 IPUT_VOLATILE
-  DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_B | DF_IFIELD | DF_LVN,
+  DF_UA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
 
   // E5 SGET_VOLATILE
   DF_DA | DF_SFIELD | DF_UMS,
@@ -724,13 +724,13 @@
   DF_UA | DF_SFIELD | DF_UMS,
 
   // E7 IGET_OBJECT_VOLATILE
-  DF_DA | DF_UB | DF_NULL_CHK_0 | DF_REF_A | DF_REF_B | DF_IFIELD | DF_LVN,
+  DF_DA | DF_UB | DF_NULL_CHK_B | DF_REF_A | DF_REF_B | DF_IFIELD | DF_LVN,
 
   // E8 IGET_WIDE_VOLATILE
-  DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_0 | DF_REF_B | DF_IFIELD | DF_LVN,
+  DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
 
   // E9 IPUT_WIDE_VOLATILE
-  DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_2 | DF_REF_B | DF_IFIELD | DF_LVN,
+  DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN,
 
   // EA SGET_WIDE_VOLATILE
   DF_DA | DF_A_WIDE | DF_SFIELD | DF_UMS,
@@ -751,28 +751,28 @@
   DF_FORMAT_3RC,
 
   // F0 INVOKE_OBJECT_INIT_RANGE
-  DF_NOP | DF_NULL_CHK_0,
+  DF_NOP,
 
   // F1 RETURN_VOID_BARRIER
   DF_NOP,
 
   // F2 IGET_QUICK
-  DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IFIELD | DF_LVN,
+  DF_DA | DF_UB | DF_NULL_CHK_B | DF_IFIELD | DF_LVN,
 
   // F3 IGET_WIDE_QUICK
-  DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_0 | DF_IFIELD | DF_LVN,
+  DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_B | DF_IFIELD | DF_LVN,
 
   // F4 IGET_OBJECT_QUICK
-  DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IFIELD | DF_LVN,
+  DF_DA | DF_UB | DF_NULL_CHK_B | DF_IFIELD | DF_LVN,
 
   // F5 IPUT_QUICK
-  DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IFIELD | DF_LVN,
+  DF_UA | DF_UB | DF_NULL_CHK_B | DF_IFIELD | DF_LVN,
 
   // F6 IPUT_WIDE_QUICK
-  DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_2 | DF_IFIELD | DF_LVN,
+  DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_B | DF_IFIELD | DF_LVN,
 
   // F7 IPUT_OBJECT_QUICK
-  DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IFIELD | DF_LVN,
+  DF_UA | DF_UB | DF_NULL_CHK_B | DF_IFIELD | DF_LVN,
 
   // F8 INVOKE_VIRTUAL_QUICK
   DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS,
@@ -787,7 +787,7 @@
   DF_FORMAT_3RC | DF_NULL_CHK_OUT0 | DF_UMS,
 
   // FC IPUT_OBJECT_VOLATILE
-  DF_UA | DF_UB | DF_NULL_CHK_1 | DF_REF_A | DF_REF_B | DF_IFIELD | DF_LVN,
+  DF_UA | DF_UB | DF_NULL_CHK_B | DF_REF_A | DF_REF_B | DF_IFIELD | DF_LVN,
 
   // FD SGET_OBJECT_VOLATILE
   DF_DA | DF_REF_A | DF_SFIELD | DF_UMS,
@@ -824,7 +824,7 @@
   DF_NOP,
 
   // 108 MIR_NULL_CHECK
-  DF_UA | DF_REF_A | DF_NULL_CHK_0 | DF_LVN,
+  DF_UA | DF_REF_A | DF_NULL_CHK_A | DF_LVN,
 
   // 109 MIR_RANGE_CHECK
   0,
@@ -893,10 +893,10 @@
   0,
 
   // 11F MirOpPackedArrayGet
-  DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C | DF_LVN,
+  DF_UB | DF_UC | DF_NULL_CHK_B | DF_RANGE_CHK_C | DF_REF_B | DF_CORE_C | DF_LVN,
 
   // 120 MirOpPackedArrayPut
-  DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_REF_B | DF_CORE_C | DF_LVN,
+  DF_UB | DF_UC | DF_NULL_CHK_B | DF_RANGE_CHK_C | DF_REF_B | DF_CORE_C | DF_LVN,
 };
 
 /* Return the base virtual register for a SSA name */
@@ -1403,7 +1403,7 @@
       GetBlockName(bb, block_name1);
       GetBlockName(pred_bb, block_name2);
       DumpCFG("/sdcard/cfg/", false);
-      LOG(FATAL) << "Successor " << block_name1 << "not found from "
+      LOG(FATAL) << "Successor " << block_name1 << " not found from "
                  << block_name2;
     }
   }
diff --git a/compiler/dex/mir_field_info.h b/compiler/dex/mir_field_info.h
index 9745c41..1842a16 100644
--- a/compiler/dex/mir_field_info.h
+++ b/compiler/dex/mir_field_info.h
@@ -137,6 +137,7 @@
   // The member offset of the field, 0u if unresolved.
   MemberOffset field_offset_;
 
+  friend class NullCheckEliminationTest;
   friend class GlobalValueNumberingTest;
   friend class LocalValueNumberingTest;
 };
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc
index f0c9858..3fa80b9 100644
--- a/compiler/dex/mir_graph.cc
+++ b/compiler/dex/mir_graph.cc
@@ -86,6 +86,7 @@
       raw_use_counts_(arena->Adapter()),
       num_reachable_blocks_(0),
       max_num_reachable_blocks_(0),
+      dfs_orders_up_to_date_(false),
       dfs_order_(arena->Adapter(kArenaAllocDfsPreOrder)),
       dfs_post_order_(arena->Adapter(kArenaAllocDfsPostOrder)),
       dom_post_order_traversal_(arena->Adapter(kArenaAllocDomPostOrder)),
@@ -93,6 +94,7 @@
       topological_order_loop_ends_(arena->Adapter(kArenaAllocTopologicalSortOrder)),
       topological_order_indexes_(arena->Adapter(kArenaAllocTopologicalSortOrder)),
       topological_order_loop_head_stack_(arena->Adapter(kArenaAllocTopologicalSortOrder)),
+      max_nested_loops_(0u),
       i_dom_list_(NULL),
       temp_scoped_alloc_(),
       temp_insn_data_(nullptr),
@@ -1975,6 +1977,7 @@
   // Prepare the loop head stack for iteration.
   topological_order_loop_head_stack_.clear();
   topological_order_loop_head_stack_.reserve(max_nested_loops);
+  max_nested_loops_ = max_nested_loops;
 }
 
 bool BasicBlock::IsExceptionBlock() const {
@@ -2224,7 +2227,7 @@
   }
 }
 
-void BasicBlock::Hide(CompilationUnit* c_unit) {
+void BasicBlock::Hide(MIRGraph* mir_graph) {
   // First lets make it a dalvik bytecode block so it doesn't have any special meaning.
   block_type = kDalvikByteCode;
 
@@ -2239,7 +2242,6 @@
   first_mir_insn = nullptr;
   last_mir_insn = nullptr;
 
-  MIRGraph* mir_graph = c_unit->mir_graph.get();
   for (BasicBlockId pred_id : predecessors) {
     BasicBlock* pred_bb = mir_graph->GetBasicBlock(pred_id);
     DCHECK(pred_bb != nullptr);
@@ -2262,6 +2264,48 @@
   successor_block_list_type = kNotUsed;
 }
 
+/*
+ * Kill an unreachable block and all blocks that become unreachable by killing this one.
+ */
+void BasicBlock::KillUnreachable(MIRGraph* mir_graph) {
+  DCHECK(predecessors.empty());  // Unreachable.
+
+  // Mark as dead and hidden.
+  block_type = kDead;
+  hidden = true;
+
+  // Detach it from its MIRs so we don't generate code for them. Also detached MIRs
+  // are updated to know that they no longer have a parent.
+  for (MIR* mir = first_mir_insn; mir != nullptr; mir = mir->next) {
+    mir->bb = NullBasicBlockId;
+  }
+  first_mir_insn = nullptr;
+  last_mir_insn = nullptr;
+
+  data_flow_info = nullptr;
+
+  // Erase this bb from all children's predecessors and kill unreachable children.
+  ChildBlockIterator iter(this, mir_graph);
+  for (BasicBlock* succ_bb = iter.Next(); succ_bb != nullptr; succ_bb = iter.Next()) {
+    succ_bb->ErasePredecessor(id);
+    if (succ_bb->predecessors.empty()) {
+      succ_bb->KillUnreachable(mir_graph);
+    }
+  }
+
+  // Remove links to children.
+  fall_through = NullBasicBlockId;
+  taken = NullBasicBlockId;
+  successor_block_list_type = kNotUsed;
+
+  if (kIsDebugBuild) {
+    if (catch_entry) {
+      DCHECK_EQ(mir_graph->catches_.count(start_offset), 1u);
+      mir_graph->catches_.erase(start_offset);
+    }
+  }
+}
+
 bool BasicBlock::IsSSALiveOut(const CompilationUnit* c_unit, int ssa_reg) {
   // In order to determine if the ssa reg is live out, we scan all the MIRs. We remember
   // the last SSA number of the same dalvik register. At the end, if it is different than ssa_reg,
@@ -2333,17 +2377,34 @@
 void BasicBlock::ErasePredecessor(BasicBlockId old_pred) {
   auto pos = std::find(predecessors.begin(), predecessors.end(), old_pred);
   DCHECK(pos != predecessors.end());
-  predecessors.erase(pos);
+  // It's faster to move the back() to *pos than erase(pos).
+  *pos = predecessors.back();
+  predecessors.pop_back();
+  size_t idx = std::distance(predecessors.begin(), pos);
+  for (MIR* mir = first_mir_insn; mir != nullptr; mir = mir->next) {
+    if (static_cast<int>(mir->dalvikInsn.opcode) != kMirOpPhi) {
+      break;
+    }
+    DCHECK_EQ(mir->ssa_rep->num_uses - 1u, predecessors.size());
+    DCHECK_EQ(mir->meta.phi_incoming[idx], old_pred);
+    mir->meta.phi_incoming[idx] = mir->meta.phi_incoming[predecessors.size()];
+    mir->ssa_rep->uses[idx] = mir->ssa_rep->uses[predecessors.size()];
+    mir->ssa_rep->num_uses = predecessors.size();
+  }
 }
 
 void BasicBlock::UpdatePredecessor(BasicBlockId old_pred, BasicBlockId new_pred) {
   DCHECK_NE(new_pred, NullBasicBlockId);
   auto pos = std::find(predecessors.begin(), predecessors.end(), old_pred);
-  if (pos != predecessors.end()) {
-    *pos = new_pred;
-  } else {
-    // If not found, add it.
-    predecessors.push_back(new_pred);
+  DCHECK(pos != predecessors.end());
+  *pos = new_pred;
+  size_t idx = std::distance(predecessors.begin(), pos);
+  for (MIR* mir = first_mir_insn; mir != nullptr; mir = mir->next) {
+    if (static_cast<int>(mir->dalvikInsn.opcode) != kMirOpPhi) {
+      break;
+    }
+    DCHECK_EQ(mir->meta.phi_incoming[idx], old_pred);
+    mir->meta.phi_incoming[idx] = new_pred;
   }
 }
 
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index cc215bd..a405af1 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -49,17 +49,14 @@
   kFormat35c,
   kFormat3rc,
   kFormatExtended,       // Extended format for extended MIRs.
-  kNullCheckSrc0,        // Null check of uses[0].
-  kNullCheckSrc1,        // Null check of uses[1].
-  kNullCheckSrc2,        // Null check of uses[2].
+  kNullCheckA,           // Null check of A.
+  kNullCheckB,           // Null check of B.
   kNullCheckOut0,        // Null check out outgoing arg0.
   kDstNonNull,           // May assume dst is non-null.
   kRetNonNull,           // May assume retval is non-null.
   kNullTransferSrc0,     // Object copy src[0] -> dst.
   kNullTransferSrcN,     // Phi null check state transfer.
-  kRangeCheckSrc1,       // Range check of uses[1].
-  kRangeCheckSrc2,       // Range check of uses[2].
-  kRangeCheckSrc3,       // Range check of uses[3].
+  kRangeCheckC,          // Range check of C.
   kFPA,
   kFPB,
   kFPC,
@@ -88,17 +85,14 @@
 #define DF_FORMAT_35C           (UINT64_C(1) << kFormat35c)
 #define DF_FORMAT_3RC           (UINT64_C(1) << kFormat3rc)
 #define DF_FORMAT_EXTENDED      (UINT64_C(1) << kFormatExtended)
-#define DF_NULL_CHK_0           (UINT64_C(1) << kNullCheckSrc0)
-#define DF_NULL_CHK_1           (UINT64_C(1) << kNullCheckSrc1)
-#define DF_NULL_CHK_2           (UINT64_C(1) << kNullCheckSrc2)
+#define DF_NULL_CHK_A           (UINT64_C(1) << kNullCheckA)
+#define DF_NULL_CHK_B           (UINT64_C(1) << kNullCheckB)
 #define DF_NULL_CHK_OUT0        (UINT64_C(1) << kNullCheckOut0)
 #define DF_NON_NULL_DST         (UINT64_C(1) << kDstNonNull)
 #define DF_NON_NULL_RET         (UINT64_C(1) << kRetNonNull)
 #define DF_NULL_TRANSFER_0      (UINT64_C(1) << kNullTransferSrc0)
 #define DF_NULL_TRANSFER_N      (UINT64_C(1) << kNullTransferSrcN)
-#define DF_RANGE_CHK_1          (UINT64_C(1) << kRangeCheckSrc1)
-#define DF_RANGE_CHK_2          (UINT64_C(1) << kRangeCheckSrc2)
-#define DF_RANGE_CHK_3          (UINT64_C(1) << kRangeCheckSrc3)
+#define DF_RANGE_CHK_C          (UINT64_C(1) << kRangeCheckC)
 #define DF_FP_A                 (UINT64_C(1) << kFPA)
 #define DF_FP_B                 (UINT64_C(1) << kFPB)
 #define DF_FP_C                 (UINT64_C(1) << kFPC)
@@ -117,14 +111,11 @@
 
 #define DF_HAS_DEFS             (DF_DA)
 
-#define DF_HAS_NULL_CHKS        (DF_NULL_CHK_0 | \
-                                 DF_NULL_CHK_1 | \
-                                 DF_NULL_CHK_2 | \
+#define DF_HAS_NULL_CHKS        (DF_NULL_CHK_A | \
+                                 DF_NULL_CHK_B | \
                                  DF_NULL_CHK_OUT0)
 
-#define DF_HAS_RANGE_CHKS       (DF_RANGE_CHK_1 | \
-                                 DF_RANGE_CHK_2 | \
-                                 DF_RANGE_CHK_3)
+#define DF_HAS_RANGE_CHKS       (DF_RANGE_CHK_C)
 
 #define DF_HAS_NR_CHKS          (DF_HAS_NULL_CHKS | \
                                  DF_HAS_RANGE_CHKS)
@@ -132,9 +123,10 @@
 #define DF_A_IS_REG             (DF_UA | DF_DA)
 #define DF_B_IS_REG             (DF_UB)
 #define DF_C_IS_REG             (DF_UC)
-#define DF_IS_GETTER_OR_SETTER  (DF_IS_GETTER | DF_IS_SETTER)
 #define DF_USES_FP              (DF_FP_A | DF_FP_B | DF_FP_C)
 #define DF_NULL_TRANSFER        (DF_NULL_TRANSFER_0 | DF_NULL_TRANSFER_N)
+#define DF_IS_INVOKE            (DF_FORMAT_35C | DF_FORMAT_3RC)
+
 enum OatMethodAttributes {
   kIsLeaf,            // Method is leaf.
   kHasLoop,           // Method contains simple loop.
@@ -160,6 +152,7 @@
 #define MIR_CALLEE                      (1 << kMIRCallee)
 #define MIR_IGNORE_SUSPEND_CHECK        (1 << kMIRIgnoreSuspendCheck)
 #define MIR_DUP                         (1 << kMIRDup)
+#define MIR_MARK                        (1 << kMIRMark)
 #define MIR_STORE_NON_TEMPORAL          (1 << kMIRStoreNonTemporal)
 
 #define BLOCK_NAME_LEN 80
@@ -422,7 +415,12 @@
    *          remove itself from any predecessor edges, remove itself from any
    *          child's predecessor array.
    */
-  void Hide(CompilationUnit* c_unit);
+  void Hide(MIRGraph* mir_graph);
+
+  /**
+   *  @brief Kill the unreachable block and all blocks that become unreachable by killing this one.
+   */
+  void KillUnreachable(MIRGraph* mir_graph);
 
   /**
    * @brief Is ssa_reg the last SSA definition of that VR in the block?
@@ -710,6 +708,10 @@
     return &topological_order_loop_head_stack_;
   }
 
+  size_t GetMaxNestedLoops() const {
+    return max_nested_loops_;
+  }
+
   bool IsConst(int32_t s_reg) const {
     return is_constant_v_->IsBitSet(s_reg);
   }
@@ -1015,6 +1017,10 @@
     return GetFirstSpecialTempVR() + max_available_special_compiler_temps_;
   }
 
+  bool HasTryCatchBlocks() const {
+    return current_code_item_->tries_size_ != 0;
+  }
+
   void DumpCheckStats();
   MIR* FindMoveResult(BasicBlock* bb, MIR* mir);
   int SRegToVReg(int ssa_reg) const;
@@ -1150,6 +1156,10 @@
   void InsertPhiNodes();
   void DoDFSPreOrderSSARename(BasicBlock* block);
 
+  bool DfsOrdersUpToDate() const {
+    return dfs_orders_up_to_date_;
+  }
+
   /*
    * IsDebugBuild sanity check: keep track of the Dex PCs for catch entries so that later on
    * we can verify that all catch entries have native PC entries.
@@ -1246,6 +1256,7 @@
   ArenaVector<uint32_t> raw_use_counts_;  // Not weighted
   unsigned int num_reachable_blocks_;
   unsigned int max_num_reachable_blocks_;
+  bool dfs_orders_up_to_date_;
   ArenaVector<BasicBlockId> dfs_order_;
   ArenaVector<BasicBlockId> dfs_post_order_;
   ArenaVector<BasicBlockId> dom_post_order_traversal_;
@@ -1258,6 +1269,7 @@
   ArenaVector<uint16_t> topological_order_indexes_;
   // Stack of the loop head indexes and recalculation flags for RepeatingTopologicalSortIterator.
   ArenaVector<std::pair<uint16_t, bool>> topological_order_loop_head_stack_;
+  size_t max_nested_loops_;
   int* i_dom_list_;
   std::unique_ptr<ScopedArenaAllocator> temp_scoped_alloc_;
   uint16_t* temp_insn_data_;
@@ -1306,7 +1318,9 @@
   static const uint64_t oat_data_flow_attributes_[kMirOpLast];
   ArenaVector<BasicBlock*> gen_suspend_test_list_;  // List of blocks containing suspend tests
 
+  friend class MirOptimizationTest;
   friend class ClassInitCheckEliminationTest;
+  friend class NullCheckEliminationTest;
   friend class GlobalValueNumberingTest;
   friend class LocalValueNumberingTest;
   friend class TopologicalSortOrderTest;
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc
index 322b737..96505ab 100644
--- a/compiler/dex/mir_optimization.cc
+++ b/compiler/dex/mir_optimization.cc
@@ -408,14 +408,14 @@
   if (bb->block_type == kDead) {
     return true;
   }
-  // Don't do a separate LVN if we did the GVN.
-  bool use_lvn = bb->use_lvn && (cu_->disable_opt & (1u << kGlobalValueNumbering)) != 0u;
+  bool use_lvn = bb->use_lvn && (cu_->disable_opt & (1u << kLocalValueNumbering)) == 0u;
   std::unique_ptr<ScopedArenaAllocator> allocator;
   std::unique_ptr<GlobalValueNumbering> global_valnum;
   std::unique_ptr<LocalValueNumbering> local_valnum;
   if (use_lvn) {
     allocator.reset(ScopedArenaAllocator::Create(&cu_->arena_stack));
-    global_valnum.reset(new (allocator.get()) GlobalValueNumbering(cu_, allocator.get()));
+    global_valnum.reset(new (allocator.get()) GlobalValueNumbering(cu_, allocator.get(),
+                                                                   GlobalValueNumbering::kModeLvn));
     local_valnum.reset(new (allocator.get()) LocalValueNumbering(global_valnum.get(), bb->id,
                                                                  allocator.get()));
   }
@@ -752,51 +752,101 @@
 /* Combine any basic blocks terminated by instructions that we now know can't throw */
 void MIRGraph::CombineBlocks(struct BasicBlock* bb) {
   // Loop here to allow combining a sequence of blocks
-  while (true) {
-    // Check termination conditions
-    if ((bb->first_mir_insn == NULL)
-        || (bb->data_flow_info == NULL)
-        || (bb->block_type == kExceptionHandling)
-        || (bb->block_type == kExitBlock)
-        || (bb->block_type == kDead)
-        || (bb->taken == NullBasicBlockId)
-        || (GetBasicBlock(bb->taken)->block_type != kExceptionHandling)
-        || (bb->successor_block_list_type != kNotUsed)
-        || (static_cast<int>(bb->last_mir_insn->dalvikInsn.opcode) != kMirOpCheck)) {
+  while ((bb->block_type == kDalvikByteCode) &&
+      (bb->last_mir_insn != nullptr) &&
+      (static_cast<int>(bb->last_mir_insn->dalvikInsn.opcode) == kMirOpCheck)) {
+    MIR* mir = bb->last_mir_insn;
+    DCHECK(bb->first_mir_insn !=  nullptr);
+
+    // Grab the attributes from the paired opcode.
+    MIR* throw_insn = mir->meta.throw_insn;
+    uint64_t df_attributes = GetDataFlowAttributes(throw_insn);
+
+    // Don't combine if the throw_insn can still throw NPE.
+    if ((df_attributes & DF_HAS_NULL_CHKS) != 0 &&
+        (throw_insn->optimization_flags & MIR_IGNORE_NULL_CHECK) == 0) {
+      break;
+    }
+    // Now whitelist specific instructions.
+    bool ok = false;
+    if ((df_attributes & DF_IFIELD) != 0) {
+      // Combine only if fast, otherwise weird things can happen.
+      const MirIFieldLoweringInfo& field_info = GetIFieldLoweringInfo(throw_insn);
+      ok = (df_attributes & DF_DA)  ? field_info.FastPut() : field_info.FastGet();
+    } else if ((df_attributes & DF_SFIELD) != 0) {
+      // Combine only if fast, otherwise weird things can happen.
+      const MirSFieldLoweringInfo& field_info = GetSFieldLoweringInfo(throw_insn);
+      bool fast = ((df_attributes & DF_DA)  ? field_info.FastPut() : field_info.FastGet());
+      // Don't combine if the SGET/SPUT can call <clinit>().
+      bool clinit = !field_info.IsInitialized() &&
+          (throw_insn->optimization_flags & MIR_IGNORE_CLINIT_CHECK) == 0;
+      ok = fast && !clinit;
+    } else if ((df_attributes & DF_HAS_RANGE_CHKS) != 0) {
+      // Only AGET/APUT have range checks. We have processed the AGET/APUT null check above.
+      DCHECK_NE(throw_insn->optimization_flags & MIR_IGNORE_NULL_CHECK, 0);
+      ok = ((throw_insn->optimization_flags & MIR_IGNORE_RANGE_CHECK) != 0);
+    } else if ((throw_insn->dalvikInsn.FlagsOf() & Instruction::kThrow) == 0) {
+      // We can encounter a non-throwing insn here thanks to inlining or other optimizations.
+      ok = true;
+    } else if (throw_insn->dalvikInsn.opcode == Instruction::ARRAY_LENGTH ||
+        throw_insn->dalvikInsn.opcode == Instruction::FILL_ARRAY_DATA ||
+        static_cast<int>(throw_insn->dalvikInsn.opcode) == kMirOpNullCheck) {
+      // No more checks for these (null check was processed above).
+      ok = true;
+    }
+    if (!ok) {
       break;
     }
 
-    // Test the kMirOpCheck instruction
-    MIR* mir = bb->last_mir_insn;
-    // Grab the attributes from the paired opcode
-    MIR* throw_insn = mir->meta.throw_insn;
-    uint64_t df_attributes = GetDataFlowAttributes(throw_insn);
-    bool can_combine = true;
-    if (df_attributes & DF_HAS_NULL_CHKS) {
-      can_combine &= ((throw_insn->optimization_flags & MIR_IGNORE_NULL_CHECK) != 0);
-    }
-    if (df_attributes & DF_HAS_RANGE_CHKS) {
-      can_combine &= ((throw_insn->optimization_flags & MIR_IGNORE_RANGE_CHECK) != 0);
-    }
-    if (!can_combine) {
-      break;
-    }
     // OK - got one.  Combine
     BasicBlock* bb_next = GetBasicBlock(bb->fall_through);
     DCHECK(!bb_next->catch_entry);
-    DCHECK_EQ(Predecessors(bb_next), 1U);
-    // Overwrite the kOpCheck insn with the paired opcode
+    DCHECK_EQ(bb_next->predecessors.size(), 1u);
+    // Overwrite the kMirOpCheck insn with the paired opcode.
     DCHECK_EQ(bb_next->first_mir_insn, throw_insn);
     *bb->last_mir_insn = *throw_insn;
+    // And grab the rest of the instructions from bb_next.
+    bb->last_mir_insn = bb_next->last_mir_insn;
+    throw_insn->next = nullptr;
+    bb_next->last_mir_insn = throw_insn;
+    // Mark acquired instructions as belonging to bb.
+    for (MIR* insn = mir; insn != nullptr; insn = insn->next) {
+      insn->bb = bb->id;
+    }
+    // Before we overwrite successors, remove their predecessor links to bb.
+    bb_next->ErasePredecessor(bb->id);
+    if (bb->taken != NullBasicBlockId) {
+      DCHECK_EQ(bb->successor_block_list_type, kNotUsed);
+      BasicBlock* bb_taken = GetBasicBlock(bb->taken);
+      // bb->taken will be overwritten below.
+      DCHECK_EQ(bb_taken->block_type, kExceptionHandling);
+      DCHECK_EQ(bb_taken->predecessors.size(), 1u);
+      DCHECK_EQ(bb_taken->predecessors[0], bb->id);
+      bb_taken->predecessors.clear();
+      bb_taken->block_type = kDead;
+      DCHECK(bb_taken->data_flow_info == nullptr);
+    } else {
+      DCHECK_EQ(bb->successor_block_list_type, kCatch);
+      for (SuccessorBlockInfo* succ_info : bb->successor_blocks) {
+        if (succ_info->block != NullBasicBlockId) {
+          BasicBlock* succ_bb = GetBasicBlock(succ_info->block);
+          DCHECK(succ_bb->catch_entry);
+          succ_bb->ErasePredecessor(bb->id);
+          if (succ_bb->predecessors.empty()) {
+            succ_bb->KillUnreachable(this);
+          }
+        }
+      }
+    }
     // Use the successor info from the next block
     bb->successor_block_list_type = bb_next->successor_block_list_type;
     bb->successor_blocks.swap(bb_next->successor_blocks);  // Swap instead of copying.
+    bb_next->successor_block_list_type = kNotUsed;
     // Use the ending block linkage from the next block
     bb->fall_through = bb_next->fall_through;
-    GetBasicBlock(bb->taken)->block_type = kDead;  // Kill the unused exception block
+    bb_next->fall_through = NullBasicBlockId;
     bb->taken = bb_next->taken;
-    // Include the rest of the instructions
-    bb->last_mir_insn = bb_next->last_mir_insn;
+    bb_next->taken = NullBasicBlockId;
     /*
      * If lower-half of pair of blocks to combine contained
      * a return or a conditional branch or an explicit throw,
@@ -805,15 +855,30 @@
     bb->terminated_by_return = bb_next->terminated_by_return;
     bb->conditional_branch = bb_next->conditional_branch;
     bb->explicit_throw = bb_next->explicit_throw;
+    // Merge the use_lvn flag.
+    bb->use_lvn |= bb_next->use_lvn;
+
+    // Kill the unused block.
+    bb_next->data_flow_info = nullptr;
 
     /*
      * NOTE: we aren't updating all dataflow info here.  Should either make sure this pass
      * happens after uses of i_dominated, dom_frontier or update the dataflow info here.
+     * NOTE: GVN uses bb->data_flow_info->live_in_v which is unaffected by the block merge.
      */
 
-    // Kill bb_next and remap now-dead id to parent
+    // Kill bb_next and remap now-dead id to parent.
     bb_next->block_type = kDead;
+    bb_next->data_flow_info = nullptr;  // Must be null for dead blocks. (Relied on by the GVN.)
     block_id_map_.Overwrite(bb_next->id, bb->id);
+    // Update predecessors in children.
+    ChildBlockIterator iter(bb, this);
+    for (BasicBlock* child = iter.Next(); child != nullptr; child = iter.Next()) {
+      child->UpdatePredecessor(bb_next->id, bb->id);
+    }
+
+    // DFS orders are not up to date anymore.
+    dfs_orders_up_to_date_ = false;
 
     // Now, loop back and see if we can keep going
   }
@@ -827,12 +892,21 @@
 
   DCHECK(temp_scoped_alloc_.get() == nullptr);
   temp_scoped_alloc_.reset(ScopedArenaAllocator::Create(&cu_->arena_stack));
-  temp_bit_vector_size_ = GetNumSSARegs();
+  temp_bit_vector_size_ = GetNumOfCodeVRs();
   temp_bit_vector_ = new (temp_scoped_alloc_.get()) ArenaBitVector(
       temp_scoped_alloc_.get(), temp_bit_vector_size_, false, kBitMapNullCheck);
   temp_bit_matrix_ = static_cast<ArenaBitVector**>(
       temp_scoped_alloc_->Alloc(sizeof(ArenaBitVector*) * GetNumBlocks(), kArenaAllocMisc));
   std::fill_n(temp_bit_matrix_, GetNumBlocks(), nullptr);
+
+  // reset MIR_MARK
+  AllNodesIterator iter(this);
+  for (BasicBlock* bb = iter.Next(); bb != nullptr; bb = iter.Next()) {
+    for (MIR* mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
+      mir->optimization_flags &= ~MIR_MARK;
+    }
+  }
+
   return true;
 }
 
@@ -840,98 +914,96 @@
  * Eliminate unnecessary null checks for a basic block.
  */
 bool MIRGraph::EliminateNullChecks(BasicBlock* bb) {
-  if (bb->data_flow_info == nullptr) return false;
+  if (bb->block_type != kDalvikByteCode && bb->block_type != kEntryBlock) {
+    // Ignore the kExitBlock as well.
+    DCHECK(bb->first_mir_insn == nullptr);
+    return false;
+  }
 
-  ArenaBitVector* ssa_regs_to_check = temp_bit_vector_;
+  ArenaBitVector* vregs_to_check = temp_bit_vector_;
   /*
    * Set initial state. Catch blocks don't need any special treatment.
    */
   if (bb->block_type == kEntryBlock) {
-    ssa_regs_to_check->ClearAllBits();
+    vregs_to_check->ClearAllBits();
     // Assume all ins are objects.
     for (uint16_t in_reg = GetFirstInVR();
          in_reg < GetNumOfCodeVRs(); in_reg++) {
-      ssa_regs_to_check->SetBit(in_reg);
+      vregs_to_check->SetBit(in_reg);
     }
     if ((cu_->access_flags & kAccStatic) == 0) {
-      // If non-static method, mark "this" as non-null
+      // If non-static method, mark "this" as non-null.
       int this_reg = GetFirstInVR();
-      ssa_regs_to_check->ClearBit(this_reg);
+      vregs_to_check->ClearBit(this_reg);
     }
-  } else if (bb->predecessors.size() == 1) {
-    BasicBlock* pred_bb = GetBasicBlock(bb->predecessors[0]);
-    // pred_bb must have already been processed at least once.
-    DCHECK(temp_bit_matrix_[pred_bb->id] != nullptr);
-    ssa_regs_to_check->Copy(temp_bit_matrix_[pred_bb->id]);
-    if (pred_bb->block_type == kDalvikByteCode) {
-      // Check to see if predecessor had an explicit null-check.
-      MIR* last_insn = pred_bb->last_mir_insn;
-      if (last_insn != nullptr) {
-        Instruction::Code last_opcode = last_insn->dalvikInsn.opcode;
-        if (last_opcode == Instruction::IF_EQZ) {
-          if (pred_bb->fall_through == bb->id) {
-            // 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.
-            ssa_regs_to_check->ClearBit(last_insn->ssa_rep->uses[0]);
-          }
-        } else if (last_opcode == Instruction::IF_NEZ) {
-          if (pred_bb->taken == bb->id) {
-            // The taken block following a IF_NEZ, set the vA of the IF_NEZ to show that it can't be
-            // null.
-            ssa_regs_to_check->ClearBit(last_insn->ssa_rep->uses[0]);
+  } else {
+    DCHECK_EQ(bb->block_type, kDalvikByteCode);
+    // Starting state is union of all incoming arcs.
+    bool copied_first = false;
+    for (BasicBlockId pred_id : bb->predecessors) {
+      if (temp_bit_matrix_[pred_id] == nullptr) {
+        continue;
+      }
+      BasicBlock* pred_bb = GetBasicBlock(pred_id);
+      DCHECK(pred_bb != nullptr);
+      MIR* null_check_insn = nullptr;
+      if (pred_bb->block_type == kDalvikByteCode) {
+        // Check to see if predecessor had an explicit null-check.
+        MIR* last_insn = pred_bb->last_mir_insn;
+        if (last_insn != nullptr) {
+          Instruction::Code last_opcode = last_insn->dalvikInsn.opcode;
+          if ((last_opcode == Instruction::IF_EQZ && pred_bb->fall_through == bb->id) ||
+              (last_opcode == Instruction::IF_NEZ && pred_bb->taken == bb->id)) {
+            // Remember the null check insn if there's no other predecessor requiring null check.
+            if (!copied_first || !vregs_to_check->IsBitSet(last_insn->dalvikInsn.vA)) {
+              null_check_insn = last_insn;
+            }
           }
         }
       }
-    }
-  } else {
-    // Starting state is union of all incoming arcs
-    bool copied_first = false;
-    for (BasicBlockId pred_id : bb->predecessors) {
-      BasicBlock* pred_bb = GetBasicBlock(pred_id);
-      DCHECK(pred_bb != nullptr);
-      DCHECK(pred_bb->data_flow_info != nullptr);
-      if (temp_bit_matrix_[pred_bb->id] == nullptr) {
-        continue;
-      }
       if (!copied_first) {
         copied_first = true;
-        ssa_regs_to_check->Copy(temp_bit_matrix_[pred_bb->id]);
+        vregs_to_check->Copy(temp_bit_matrix_[pred_id]);
       } else {
-        ssa_regs_to_check->Union(temp_bit_matrix_[pred_bb->id]);
+        vregs_to_check->Union(temp_bit_matrix_[pred_id]);
+      }
+      if (null_check_insn != nullptr) {
+        vregs_to_check->ClearBit(null_check_insn->dalvikInsn.vA);
       }
     }
     DCHECK(copied_first);  // At least one predecessor must have been processed before this bb.
   }
-  // At this point, ssa_regs_to_check shows which sregs have an object definition with
+  // At this point, vregs_to_check shows which sregs have an object definition with
   // no intervening uses.
 
   // Walk through the instruction in the block, updating as necessary
   for (MIR* mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
-    if (mir->ssa_rep == NULL) {
-        continue;
-    }
-
     uint64_t df_attributes = GetDataFlowAttributes(mir);
 
+    DCHECK_EQ(df_attributes & DF_NULL_TRANSFER_N, 0u);  // No Phis yet.
+
     // Might need a null check?
     if (df_attributes & DF_HAS_NULL_CHKS) {
-      int src_idx;
-      if (df_attributes & DF_NULL_CHK_1) {
-        src_idx = 1;
-      } else if (df_attributes & DF_NULL_CHK_2) {
-        src_idx = 2;
+      int src_vreg;
+      if (df_attributes & DF_NULL_CHK_OUT0) {
+        DCHECK_NE(df_attributes & DF_IS_INVOKE, 0u);
+        src_vreg = mir->dalvikInsn.vC;
+      } else if (df_attributes & DF_NULL_CHK_B) {
+        DCHECK_NE(df_attributes & DF_REF_B, 0u);
+        src_vreg = mir->dalvikInsn.vB;
       } else {
-        src_idx = 0;
+        DCHECK_NE(df_attributes & DF_NULL_CHK_A, 0u);
+        DCHECK_NE(df_attributes & DF_REF_A, 0u);
+        src_vreg = mir->dalvikInsn.vA;
       }
-      int src_sreg = mir->ssa_rep->uses[src_idx];
-      if (!ssa_regs_to_check->IsBitSet(src_sreg)) {
+      if (!vregs_to_check->IsBitSet(src_vreg)) {
         // Eliminate the null check.
-        mir->optimization_flags |= MIR_IGNORE_NULL_CHECK;
+        mir->optimization_flags |= MIR_MARK;
       } else {
         // Do the null check.
-        // Do not clear MIR_IGNORE_NULL_CHECK flag as it may be set by another optimization
-        // Mark s_reg as null-checked
-        ssa_regs_to_check->ClearBit(src_sreg);
+        mir->optimization_flags &= ~MIR_MARK;
+        // Mark src_vreg as null-checked.
+        vregs_to_check->ClearBit(src_vreg);
       }
     }
 
@@ -945,66 +1017,41 @@
      * Note: we can't tell if a CONST definition might be used as an object, so treat
      * them all as object definitions.
      */
-    if (((df_attributes & (DF_DA | DF_REF_A)) == (DF_DA | DF_REF_A)) ||
+    if ((df_attributes & (DF_DA | DF_REF_A)) == (DF_DA | DF_REF_A) ||
         (df_attributes & DF_SETS_CONST))  {
-      ssa_regs_to_check->SetBit(mir->ssa_rep->defs[0]);
+      vregs_to_check->SetBit(mir->dalvikInsn.vA);
     }
 
-    // Now, remove mark from all object definitions we know are non-null.
+    // Then, remove mark from all object definitions we know are non-null.
     if (df_attributes & DF_NON_NULL_DST) {
       // Mark target of NEW* as non-null
-      ssa_regs_to_check->ClearBit(mir->ssa_rep->defs[0]);
+      DCHECK_NE(df_attributes & DF_REF_A, 0u);
+      vregs_to_check->ClearBit(mir->dalvikInsn.vA);
     }
 
     // Mark non-null returns from invoke-style NEW*
     if (df_attributes & DF_NON_NULL_RET) {
       MIR* next_mir = mir->next;
       // Next should be an MOVE_RESULT_OBJECT
-      if (next_mir &&
-          next_mir->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) {
-        // Mark as null checked
-        ssa_regs_to_check->ClearBit(next_mir->ssa_rep->defs[0]);
+      if (UNLIKELY(next_mir == nullptr)) {
+        // The MethodVerifier makes sure there's no MOVE_RESULT at the catch entry or branch
+        // target, so the MOVE_RESULT cannot be broken away into another block.
+        LOG(WARNING) << "Unexpected end of block following new";
+      } else if (UNLIKELY(next_mir->dalvikInsn.opcode != Instruction::MOVE_RESULT_OBJECT)) {
+        LOG(WARNING) << "Unexpected opcode following new: " << next_mir->dalvikInsn.opcode;
       } else {
-        if (next_mir) {
-          LOG(WARNING) << "Unexpected opcode following new: " << next_mir->dalvikInsn.opcode;
-        } else if (bb->fall_through != NullBasicBlockId) {
-          // Look in next basic block
-          struct BasicBlock* next_bb = GetBasicBlock(bb->fall_through);
-          for (MIR* tmir = next_bb->first_mir_insn; tmir != NULL;
-            tmir =tmir->next) {
-            if (MIR::DecodedInstruction::IsPseudoMirOp(tmir->dalvikInsn.opcode)) {
-              continue;
-            }
-            // First non-pseudo should be MOVE_RESULT_OBJECT
-            if (tmir->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) {
-              // Mark as null checked
-              ssa_regs_to_check->ClearBit(tmir->ssa_rep->defs[0]);
-            } else {
-              LOG(WARNING) << "Unexpected op after new: " << tmir->dalvikInsn.opcode;
-            }
-            break;
-          }
-        }
+        // Mark as null checked.
+        vregs_to_check->ClearBit(next_mir->dalvikInsn.vA);
       }
     }
 
-    /*
-     * Propagate nullcheck state on register copies (including
-     * Phi pseudo copies.  For the latter, nullcheck state is
-     * the "or" of all the Phi's operands.
-     */
-    if (df_attributes & (DF_NULL_TRANSFER_0 | DF_NULL_TRANSFER_N)) {
-      int tgt_sreg = mir->ssa_rep->defs[0];
-      int operands = (df_attributes & DF_NULL_TRANSFER_0) ? 1 :
-          mir->ssa_rep->num_uses;
-      bool needs_null_check = false;
-      for (int i = 0; i < operands; i++) {
-        needs_null_check |= ssa_regs_to_check->IsBitSet(mir->ssa_rep->uses[i]);
-      }
-      if (needs_null_check) {
-        ssa_regs_to_check->SetBit(tgt_sreg);
+    // Propagate null check state on register copies.
+    if (df_attributes & DF_NULL_TRANSFER_0) {
+      DCHECK_EQ(df_attributes | ~(DF_DA | DF_REF_A | DF_UB | DF_REF_B), static_cast<uint64_t>(-1));
+      if (vregs_to_check->IsBitSet(mir->dalvikInsn.vB)) {
+        vregs_to_check->SetBit(mir->dalvikInsn.vA);
       } else {
-        ssa_regs_to_check->ClearBit(tgt_sreg);
+        vregs_to_check->ClearBit(mir->dalvikInsn.vA);
       }
     }
   }
@@ -1014,15 +1061,15 @@
   ArenaBitVector* old_ending_ssa_regs_to_check = temp_bit_matrix_[bb->id];
   if (old_ending_ssa_regs_to_check == nullptr) {
     DCHECK(temp_scoped_alloc_.get() != nullptr);
-    nce_changed = ssa_regs_to_check->GetHighestBitSet() != -1;
-    temp_bit_matrix_[bb->id] = ssa_regs_to_check;
-    // Create a new ssa_regs_to_check for next BB.
+    nce_changed = vregs_to_check->GetHighestBitSet() != -1;
+    temp_bit_matrix_[bb->id] = vregs_to_check;
+    // Create a new vregs_to_check for next BB.
     temp_bit_vector_ = new (temp_scoped_alloc_.get()) ArenaBitVector(
         temp_scoped_alloc_.get(), temp_bit_vector_size_, false, kBitMapNullCheck);
-  } else if (!ssa_regs_to_check->SameBitsSet(old_ending_ssa_regs_to_check)) {
+  } else if (!vregs_to_check->SameBitsSet(old_ending_ssa_regs_to_check)) {
     nce_changed = true;
-    temp_bit_matrix_[bb->id] = ssa_regs_to_check;
-    temp_bit_vector_ = old_ending_ssa_regs_to_check;  // Reuse for ssa_regs_to_check for next BB.
+    temp_bit_matrix_[bb->id] = vregs_to_check;
+    temp_bit_vector_ = old_ending_ssa_regs_to_check;  // Reuse for vregs_to_check for next BB.
   }
   return nce_changed;
 }
@@ -1034,6 +1081,18 @@
   temp_bit_matrix_ = nullptr;
   DCHECK(temp_scoped_alloc_.get() != nullptr);
   temp_scoped_alloc_.reset();
+
+  // converge MIR_MARK with MIR_IGNORE_NULL_CHECK
+  AllNodesIterator iter(this);
+  for (BasicBlock* bb = iter.Next(); bb != nullptr; bb = iter.Next()) {
+    for (MIR* mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
+      constexpr int kMarkToIgnoreNullCheckShift = kMIRMark - kMIRIgnoreNullCheck;
+      COMPILE_ASSERT(kMarkToIgnoreNullCheckShift > 0, check_valid_shift_right);
+      uint16_t mirMarkAdjustedToIgnoreNullCheck =
+          (mir->optimization_flags & MIR_MARK) >> kMarkToIgnoreNullCheckShift;
+      mir->optimization_flags |= mirMarkAdjustedToIgnoreNullCheck;
+    }
+  }
 }
 
 /*
@@ -1098,26 +1157,27 @@
     // First, find all SGET/SPUTs that may need class initialization checks, record INVOKE_STATICs.
     AllNodesIterator iter(this);
     for (BasicBlock* bb = iter.Next(); bb != nullptr; bb = iter.Next()) {
-      for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) {
-        DCHECK(bb->data_flow_info != nullptr);
-        if (mir->dalvikInsn.opcode >= Instruction::SGET &&
-            mir->dalvikInsn.opcode <= Instruction::SPUT_SHORT) {
-          const MirSFieldLoweringInfo& field_info = GetSFieldLoweringInfo(mir);
-          uint16_t index = 0xffffu;
-          if (!field_info.IsInitialized()) {
-            DCHECK_LT(class_to_index_map.size(), 0xffffu);
-            MapEntry entry = {
-                // Treat unresolved fields as if each had its own class.
-                field_info.IsResolved() ? field_info.DeclaringDexFile()
-                                        : nullptr,
-                field_info.IsResolved() ? field_info.DeclaringClassIndex()
-                                        : field_info.FieldIndex(),
-                static_cast<uint16_t>(class_to_index_map.size())
-            };
-            index = class_to_index_map.insert(entry).first->index;
+      if (bb->block_type == kDalvikByteCode) {
+        for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) {
+          if (mir->dalvikInsn.opcode >= Instruction::SGET &&
+              mir->dalvikInsn.opcode <= Instruction::SPUT_SHORT) {
+            const MirSFieldLoweringInfo& field_info = GetSFieldLoweringInfo(mir);
+            uint16_t index = 0xffffu;
+            if (!field_info.IsInitialized()) {
+              DCHECK_LT(class_to_index_map.size(), 0xffffu);
+              MapEntry entry = {
+                  // Treat unresolved fields as if each had its own class.
+                  field_info.IsResolved() ? field_info.DeclaringDexFile()
+                                          : nullptr,
+                  field_info.IsResolved() ? field_info.DeclaringClassIndex()
+                                          : field_info.FieldIndex(),
+                  static_cast<uint16_t>(class_to_index_map.size())
+              };
+              index = class_to_index_map.insert(entry).first->index;
+            }
+            // Using offset/2 for index into temp_insn_data_.
+            temp_insn_data_[mir->offset / 2u] = index;
           }
-          // Using offset/2 for index into temp_insn_data_.
-          temp_insn_data_[mir->offset / 2u] = index;
         }
       }
     }
@@ -1146,7 +1206,9 @@
  */
 bool MIRGraph::EliminateClassInitChecks(BasicBlock* bb) {
   DCHECK_EQ((cu_->disable_opt & (1 << kClassInitCheckElimination)), 0u);
-  if (bb->data_flow_info == nullptr) {
+  if (bb->block_type != kDalvikByteCode && bb->block_type != kEntryBlock) {
+    // Ignore the kExitBlock as well.
+    DCHECK(bb->first_mir_insn == nullptr);
     return false;
   }
 
@@ -1161,7 +1223,6 @@
     BasicBlock* pred_bb = GetBasicBlock(bb->predecessors[0]);
     // pred_bb must have already been processed at least once.
     DCHECK(pred_bb != nullptr);
-    DCHECK(pred_bb->data_flow_info != nullptr);
     DCHECK(temp_bit_matrix_[pred_bb->id] != nullptr);
     classes_to_check->Copy(temp_bit_matrix_[pred_bb->id]);
   } else {
@@ -1170,7 +1231,6 @@
     for (BasicBlockId pred_id : bb->predecessors) {
       BasicBlock* pred_bb = GetBasicBlock(pred_id);
       DCHECK(pred_bb != nullptr);
-      DCHECK(pred_bb->data_flow_info != nullptr);
       if (temp_bit_matrix_[pred_bb->id] == nullptr) {
         continue;
       }
@@ -1237,7 +1297,7 @@
 }
 
 bool MIRGraph::ApplyGlobalValueNumberingGate() {
-  if ((cu_->disable_opt & (1u << kGlobalValueNumbering)) != 0u) {
+  if (GlobalValueNumbering::Skip(cu_)) {
     return false;
   }
 
@@ -1245,7 +1305,8 @@
   temp_scoped_alloc_.reset(ScopedArenaAllocator::Create(&cu_->arena_stack));
   DCHECK(temp_gvn_ == nullptr);
   temp_gvn_.reset(
-      new (temp_scoped_alloc_.get()) GlobalValueNumbering(cu_, temp_scoped_alloc_.get()));
+      new (temp_scoped_alloc_.get()) GlobalValueNumbering(cu_, temp_scoped_alloc_.get(),
+                                                          GlobalValueNumbering::kModeGvn));
   return true;
 }
 
@@ -1264,19 +1325,23 @@
 void MIRGraph::ApplyGlobalValueNumberingEnd() {
   // Perform modifications.
   if (temp_gvn_->Good()) {
-    temp_gvn_->AllowModifications();
-    PreOrderDfsIterator iter(this);
-    for (BasicBlock* bb = iter.Next(); bb != nullptr; bb = iter.Next()) {
-      ScopedArenaAllocator allocator(&cu_->arena_stack);  // Reclaim memory after each LVN.
-      LocalValueNumbering* lvn = temp_gvn_->PrepareBasicBlock(bb, &allocator);
-      if (lvn != nullptr) {
-        for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) {
-          lvn->GetValueNumber(mir);
+    if (max_nested_loops_ != 0u) {
+      temp_gvn_->StartPostProcessing();
+      TopologicalSortIterator iter(this);
+      for (BasicBlock* bb = iter.Next(); bb != nullptr; bb = iter.Next()) {
+        ScopedArenaAllocator allocator(&cu_->arena_stack);  // Reclaim memory after each LVN.
+        LocalValueNumbering* lvn = temp_gvn_->PrepareBasicBlock(bb, &allocator);
+        if (lvn != nullptr) {
+          for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) {
+            lvn->GetValueNumber(mir);
+          }
+          bool change = temp_gvn_->FinishBasicBlock(bb);
+          DCHECK(!change) << PrettyMethod(cu_->method_idx, *cu_->dex_file);
         }
-        bool change = temp_gvn_->FinishBasicBlock(bb);
-        DCHECK(!change) << PrettyMethod(cu_->method_idx, *cu_->dex_file);
       }
     }
+    // GVN was successful, running the LVN would be useless.
+    cu_->disable_opt |= (1u << kLocalValueNumbering);
   } else {
     LOG(WARNING) << "GVN failed for " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
   }
diff --git a/compiler/dex/mir_optimization_test.cc b/compiler/dex/mir_optimization_test.cc
index 55e547e..337d4ef 100644
--- a/compiler/dex/mir_optimization_test.cc
+++ b/compiler/dex/mir_optimization_test.cc
@@ -23,15 +23,8 @@
 
 namespace art {
 
-class ClassInitCheckEliminationTest : public testing::Test {
+class MirOptimizationTest : public testing::Test {
  protected:
-  struct SFieldDef {
-    uint16_t field_idx;
-    uintptr_t declaring_dex_file;
-    uint16_t declaring_class_idx;
-    uint16_t declaring_field_idx;
-  };
-
   struct BBDef {
     static constexpr size_t kMaxSuccessors = 4;
     static constexpr size_t kMaxPredecessors = 4;
@@ -44,9 +37,12 @@
   };
 
   struct MIRDef {
-    Instruction::Code opcode;
     BasicBlockId bbid;
-    uint32_t field_or_method_info;
+    Instruction::Code opcode;
+    uint32_t field_info;
+    uint32_t vA;
+    uint32_t vB;
+    uint32_t vC;
   };
 
 #define DEF_SUCC0() \
@@ -72,32 +68,6 @@
 #define DEF_BB(type, succ, pred) \
     { type, succ, pred }
 
-#define DEF_MIR(opcode, bb, field_info) \
-    { opcode, bb, field_info }
-
-  void DoPrepareSFields(const SFieldDef* defs, size_t count) {
-    cu_.mir_graph->sfield_lowering_infos_.clear();
-    cu_.mir_graph->sfield_lowering_infos_.reserve(count);
-    for (size_t i = 0u; i != count; ++i) {
-      const SFieldDef* def = &defs[i];
-      MirSFieldLoweringInfo field_info(def->field_idx);
-      if (def->declaring_dex_file != 0u) {
-        field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
-        field_info.declaring_class_idx_ = def->declaring_class_idx;
-        field_info.declaring_field_idx_ = def->declaring_field_idx;
-        field_info.flags_ = MirSFieldLoweringInfo::kFlagIsStatic;
-      }
-      ASSERT_EQ(def->declaring_dex_file != 0u, field_info.IsResolved());
-      ASSERT_FALSE(field_info.IsInitialized());
-      cu_.mir_graph->sfield_lowering_infos_.push_back(field_info);
-    }
-  }
-
-  template <size_t count>
-  void PrepareSFields(const SFieldDef (&defs)[count]) {
-    DoPrepareSFields(defs, count);
-  }
-
   void DoPrepareBasicBlocks(const BBDef* defs, size_t count) {
     cu_.mir_graph->block_id_map_.clear();
     cu_.mir_graph->block_list_.clear();
@@ -145,6 +115,63 @@
     DoPrepareBasicBlocks(defs, count);
   }
 
+  void PrepareSingleBlock() {
+    static const BBDef bbs[] = {
+        DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
+        DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
+        DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(3)),
+        DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(1)),
+    };
+    PrepareBasicBlocks(bbs);
+  }
+
+  void PrepareDiamond() {
+    static const BBDef bbs[] = {
+        DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
+        DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
+        DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
+        DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 5), DEF_PRED1(1)),
+        DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)),
+        DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)),
+        DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED2(4, 5)),
+    };
+    PrepareBasicBlocks(bbs);
+  }
+
+  void PrepareLoop() {
+    static const BBDef bbs[] = {
+        DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
+        DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
+        DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(5)),
+        DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),
+        DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 4), DEF_PRED2(3, 4)),  // "taken" loops to self.
+        DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(4)),
+    };
+    PrepareBasicBlocks(bbs);
+  }
+
+  void PrepareCatch() {
+    static const BBDef bbs[] = {
+        DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
+        DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
+        DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
+        DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),     // The top.
+        DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)),     // The throwing insn.
+        DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)),     // Catch handler.
+        DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED2(4, 5)),  // The merged block.
+    };
+    PrepareBasicBlocks(bbs);
+    BasicBlock* catch_handler = cu_.mir_graph->GetBasicBlock(5u);
+    catch_handler->catch_entry = true;
+    // Add successor block info to the check block.
+    BasicBlock* check_bb = cu_.mir_graph->GetBasicBlock(3u);
+    check_bb->successor_block_list_type = kCatch;
+    SuccessorBlockInfo* successor_block_info = reinterpret_cast<SuccessorBlockInfo*>
+        (cu_.arena.Alloc(sizeof(SuccessorBlockInfo), kArenaAllocSuccessor));
+    successor_block_info->block = catch_handler->id;
+    check_bb->successor_blocks.push_back(successor_block_info);
+  }
+
   void DoPrepareMIRs(const MIRDef* defs, size_t count) {
     mir_count_ = count;
     mirs_ = reinterpret_cast<MIR*>(cu_.arena.Alloc(sizeof(MIR) * count, kArenaAllocMIR));
@@ -157,9 +184,15 @@
       BasicBlock* bb = cu_.mir_graph->block_list_[def->bbid];
       bb->AppendMIR(mir);
       if (def->opcode >= Instruction::SGET && def->opcode <= Instruction::SPUT_SHORT) {
-        ASSERT_LT(def->field_or_method_info, cu_.mir_graph->sfield_lowering_infos_.size());
-        mir->meta.sfield_lowering_info = def->field_or_method_info;
+        ASSERT_LT(def->field_info, cu_.mir_graph->sfield_lowering_infos_.size());
+        mir->meta.sfield_lowering_info = def->field_info;
+      } else if (def->opcode >= Instruction::IGET && def->opcode <= Instruction::IPUT_SHORT) {
+        ASSERT_LT(def->field_info, cu_.mir_graph->ifield_lowering_infos_.size());
+        mir->meta.ifield_lowering_info = def->field_info;
       }
+      mir->dalvikInsn.vA = def->vA;
+      mir->dalvikInsn.vB = def->vB;
+      mir->dalvikInsn.vC = def->vC;
       mir->ssa_rep = nullptr;
       mir->offset = 2 * i;  // All insns need to be at least 2 code units long.
       mir->optimization_flags = 0u;
@@ -179,29 +212,14 @@
     DoPrepareMIRs(defs, count);
   }
 
-  void PerformClassInitCheckElimination() {
-    cu_.mir_graph->SSATransformationStart();
-    cu_.mir_graph->ComputeDFSOrders();
-    cu_.mir_graph->ComputeDominators();
-    cu_.mir_graph->ComputeTopologicalSortOrder();
-    cu_.mir_graph->SSATransformationEnd();
-    bool gate_result = cu_.mir_graph->EliminateClassInitChecksGate();
-    ASSERT_TRUE(gate_result);
-    LoopRepeatingTopologicalSortIterator iterator(cu_.mir_graph.get());
-    bool change = false;
-    for (BasicBlock* bb = iterator.Next(change); bb != nullptr; bb = iterator.Next(change)) {
-      change = cu_.mir_graph->EliminateClassInitChecks(bb);
-    }
-    cu_.mir_graph->EliminateClassInitChecksEnd();
-  }
-
-  ClassInitCheckEliminationTest()
+  MirOptimizationTest()
       : pool_(),
         cu_(&pool_),
         mir_count_(0u),
         mirs_(nullptr),
         code_item_(nullptr) {
     cu_.mir_graph.reset(new MIRGraph(&cu_, &cu_.arena));
+    cu_.access_flags = kAccStatic;  // Don't let "this" interfere with this test.
   }
 
   ArenaPool pool_;
@@ -211,6 +229,109 @@
   DexFile::CodeItem* code_item_;
 };
 
+class ClassInitCheckEliminationTest : public MirOptimizationTest {
+ protected:
+  struct SFieldDef {
+    uint16_t field_idx;
+    uintptr_t declaring_dex_file;
+    uint16_t declaring_class_idx;
+    uint16_t declaring_field_idx;
+  };
+
+  void DoPrepareSFields(const SFieldDef* defs, size_t count) {
+    cu_.mir_graph->sfield_lowering_infos_.clear();
+    cu_.mir_graph->sfield_lowering_infos_.reserve(count);
+    for (size_t i = 0u; i != count; ++i) {
+      const SFieldDef* def = &defs[i];
+      MirSFieldLoweringInfo field_info(def->field_idx);
+      if (def->declaring_dex_file != 0u) {
+        field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
+        field_info.declaring_class_idx_ = def->declaring_class_idx;
+        field_info.declaring_field_idx_ = def->declaring_field_idx;
+        field_info.flags_ = MirSFieldLoweringInfo::kFlagIsStatic;
+      }
+      ASSERT_EQ(def->declaring_dex_file != 0u, field_info.IsResolved());
+      ASSERT_FALSE(field_info.IsInitialized());
+      cu_.mir_graph->sfield_lowering_infos_.push_back(field_info);
+    }
+  }
+
+  template <size_t count>
+  void PrepareSFields(const SFieldDef (&defs)[count]) {
+    DoPrepareSFields(defs, count);
+  }
+
+  void PerformClassInitCheckElimination() {
+    cu_.mir_graph->ComputeDFSOrders();
+    bool gate_result = cu_.mir_graph->EliminateClassInitChecksGate();
+    ASSERT_TRUE(gate_result);
+    RepeatingPreOrderDfsIterator iterator(cu_.mir_graph.get());
+    bool change = false;
+    for (BasicBlock* bb = iterator.Next(change); bb != nullptr; bb = iterator.Next(change)) {
+      change = cu_.mir_graph->EliminateClassInitChecks(bb);
+    }
+    cu_.mir_graph->EliminateClassInitChecksEnd();
+  }
+
+  ClassInitCheckEliminationTest()
+      : MirOptimizationTest() {
+  }
+};
+
+class NullCheckEliminationTest : public MirOptimizationTest {
+ protected:
+  struct IFieldDef {
+    uint16_t field_idx;
+    uintptr_t declaring_dex_file;
+    uint16_t declaring_class_idx;
+    uint16_t declaring_field_idx;
+  };
+
+  void DoPrepareIFields(const IFieldDef* defs, size_t count) {
+    cu_.mir_graph->ifield_lowering_infos_.clear();
+    cu_.mir_graph->ifield_lowering_infos_.reserve(count);
+    for (size_t i = 0u; i != count; ++i) {
+      const IFieldDef* def = &defs[i];
+      MirIFieldLoweringInfo field_info(def->field_idx);
+      if (def->declaring_dex_file != 0u) {
+        field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
+        field_info.declaring_class_idx_ = def->declaring_class_idx;
+        field_info.declaring_field_idx_ = def->declaring_field_idx;
+      }
+      ASSERT_EQ(def->declaring_dex_file != 0u, field_info.IsResolved());
+      cu_.mir_graph->ifield_lowering_infos_.push_back(field_info);
+    }
+  }
+
+  template <size_t count>
+  void PrepareIFields(const IFieldDef (&defs)[count]) {
+    DoPrepareIFields(defs, count);
+  }
+
+  void PerformNullCheckElimination() {
+    // Make vregs in range [100, 1000) input registers, i.e. requiring a null check.
+    code_item_->registers_size_ = 1000;
+    code_item_->ins_size_ = 900;
+
+    cu_.mir_graph->ComputeDFSOrders();
+    bool gate_result = cu_.mir_graph->EliminateNullChecksGate();
+    ASSERT_TRUE(gate_result);
+    RepeatingPreOrderDfsIterator iterator(cu_.mir_graph.get());
+    bool change = false;
+    for (BasicBlock* bb = iterator.Next(change); bb != nullptr; bb = iterator.Next(change)) {
+      change = cu_.mir_graph->EliminateNullChecks(bb);
+    }
+    cu_.mir_graph->EliminateNullChecksEnd();
+  }
+
+  NullCheckEliminationTest()
+      : MirOptimizationTest() {
+  }
+};
+
+#define DEF_SGET_SPUT_V0(bb, opcode, field_info) \
+    { bb, opcode, field_info, 0u, 0u, 0u }
+
 TEST_F(ClassInitCheckEliminationTest, SingleBlock) {
   static const SFieldDef sfields[] = {
       { 0u, 1u, 0u, 0u },
@@ -220,31 +341,25 @@
       { 4u, 1u, 3u, 4u },  // Same declaring class as sfield[3].
       { 5u, 0u, 0u, 0u },  // Unresolved.
   };
-  static const BBDef bbs[] = {
-      DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
-      DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
-      DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(3)),
-      DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(1)),
-  };
   static const MIRDef mirs[] = {
-      DEF_MIR(Instruction::SPUT, 3u, 5u),  // Unresolved.
-      DEF_MIR(Instruction::SPUT, 3u, 0u),
-      DEF_MIR(Instruction::SGET, 3u, 1u),
-      DEF_MIR(Instruction::SGET, 3u, 2u),
-      DEF_MIR(Instruction::SGET, 3u, 5u),  // Unresolved.
-      DEF_MIR(Instruction::SGET, 3u, 0u),
-      DEF_MIR(Instruction::SGET, 3u, 1u),
-      DEF_MIR(Instruction::SGET, 3u, 2u),
-      DEF_MIR(Instruction::SGET, 3u, 5u),  // Unresolved.
-      DEF_MIR(Instruction::SGET, 3u, 3u),
-      DEF_MIR(Instruction::SGET, 3u, 4u),
+      DEF_SGET_SPUT_V0(3u, Instruction::SPUT, 5u),  // Unresolved.
+      DEF_SGET_SPUT_V0(3u, Instruction::SPUT, 0u),
+      DEF_SGET_SPUT_V0(3u, Instruction::SGET, 1u),
+      DEF_SGET_SPUT_V0(3u, Instruction::SGET, 2u),
+      DEF_SGET_SPUT_V0(3u, Instruction::SGET, 5u),  // Unresolved.
+      DEF_SGET_SPUT_V0(3u, Instruction::SGET, 0u),
+      DEF_SGET_SPUT_V0(3u, Instruction::SGET, 1u),
+      DEF_SGET_SPUT_V0(3u, Instruction::SGET, 2u),
+      DEF_SGET_SPUT_V0(3u, Instruction::SGET, 5u),  // Unresolved.
+      DEF_SGET_SPUT_V0(3u, Instruction::SGET, 3u),
+      DEF_SGET_SPUT_V0(3u, Instruction::SGET, 4u),
   };
   static const bool expected_ignore_clinit_check[] = {
       false, false, false, false, true, true, true, true, true, false, true
   };
 
   PrepareSFields(sfields);
-  PrepareBasicBlocks(bbs);
+  PrepareSingleBlock();
   PrepareMIRs(mirs);
   PerformClassInitCheckElimination();
   ASSERT_EQ(arraysize(expected_ignore_clinit_check), mir_count_);
@@ -268,40 +383,31 @@
       { 9u, 1u, 8u, 9u },  // Same declaring class as sfield[8].
       { 10u, 0u, 0u, 0u },  // Unresolved.
   };
-  static const BBDef bbs[] = {
-      DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
-      DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
-      DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
-      DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 5), DEF_PRED1(1)),
-      DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)),
-      DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)),
-      DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED2(4, 5)),
-  };
   static const MIRDef mirs[] = {
       // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks.
-      DEF_MIR(Instruction::SGET, 3u, 10u),  // Unresolved.
-      DEF_MIR(Instruction::SPUT, 3u, 10u),  // Unresolved.
-      DEF_MIR(Instruction::SPUT, 3u, 0u),
-      DEF_MIR(Instruction::SGET, 6u, 0u),  // Eliminated (block #3 dominates #6).
-      DEF_MIR(Instruction::SPUT, 4u, 1u),
-      DEF_MIR(Instruction::SGET, 6u, 1u),  // Not eliminated (block #4 doesn't dominate #6).
-      DEF_MIR(Instruction::SGET, 3u, 2u),
-      DEF_MIR(Instruction::SGET, 4u, 2u),  // Eliminated (block #3 dominates #4).
-      DEF_MIR(Instruction::SGET, 3u, 3u),
-      DEF_MIR(Instruction::SGET, 5u, 3u),  // Eliminated (block #3 dominates #5).
-      DEF_MIR(Instruction::SGET, 3u, 4u),
-      DEF_MIR(Instruction::SGET, 6u, 4u),  // Eliminated (block #3 dominates #6).
-      DEF_MIR(Instruction::SGET, 4u, 5u),
-      DEF_MIR(Instruction::SGET, 6u, 5u),  // Not eliminated (block #4 doesn't dominate #6).
-      DEF_MIR(Instruction::SGET, 5u, 6u),
-      DEF_MIR(Instruction::SGET, 6u, 6u),  // Not eliminated (block #5 doesn't dominate #6).
-      DEF_MIR(Instruction::SGET, 4u, 7u),
-      DEF_MIR(Instruction::SGET, 5u, 7u),
-      DEF_MIR(Instruction::SGET, 6u, 7u),  // Eliminated (initialized in both blocks #3 and #4).
-      DEF_MIR(Instruction::SGET, 4u, 8u),
-      DEF_MIR(Instruction::SGET, 5u, 9u),
-      DEF_MIR(Instruction::SGET, 6u, 8u),  // Eliminated (with sfield[9] in block #5).
-      DEF_MIR(Instruction::SPUT, 6u, 9u),  // Eliminated (with sfield[8] in block #4).
+      DEF_SGET_SPUT_V0(3u, Instruction::SGET, 10u),  // Unresolved.
+      DEF_SGET_SPUT_V0(3u, Instruction::SPUT, 10u),  // Unresolved.
+      DEF_SGET_SPUT_V0(3u, Instruction::SPUT, 0u),
+      DEF_SGET_SPUT_V0(6u, Instruction::SGET, 0u),  // Eliminated (BB #3 dominates #6).
+      DEF_SGET_SPUT_V0(4u, Instruction::SPUT, 1u),
+      DEF_SGET_SPUT_V0(6u, Instruction::SGET, 1u),  // Not eliminated (BB #4 doesn't dominate #6).
+      DEF_SGET_SPUT_V0(3u, Instruction::SGET, 2u),
+      DEF_SGET_SPUT_V0(4u, Instruction::SGET, 2u),  // Eliminated (BB #3 dominates #4).
+      DEF_SGET_SPUT_V0(3u, Instruction::SGET, 3u),
+      DEF_SGET_SPUT_V0(5u, Instruction::SGET, 3u),  // Eliminated (BB #3 dominates #5).
+      DEF_SGET_SPUT_V0(3u, Instruction::SGET, 4u),
+      DEF_SGET_SPUT_V0(6u, Instruction::SGET, 4u),  // Eliminated (BB #3 dominates #6).
+      DEF_SGET_SPUT_V0(4u, Instruction::SGET, 5u),
+      DEF_SGET_SPUT_V0(6u, Instruction::SGET, 5u),  // Not eliminated (BB #4 doesn't dominate #6).
+      DEF_SGET_SPUT_V0(5u, Instruction::SGET, 6u),
+      DEF_SGET_SPUT_V0(6u, Instruction::SGET, 6u),  // Not eliminated (BB #5 doesn't dominate #6).
+      DEF_SGET_SPUT_V0(4u, Instruction::SGET, 7u),
+      DEF_SGET_SPUT_V0(5u, Instruction::SGET, 7u),
+      DEF_SGET_SPUT_V0(6u, Instruction::SGET, 7u),  // Eliminated (initialized in both #3 and #4).
+      DEF_SGET_SPUT_V0(4u, Instruction::SGET, 8u),
+      DEF_SGET_SPUT_V0(5u, Instruction::SGET, 9u),
+      DEF_SGET_SPUT_V0(6u, Instruction::SGET, 8u),  // Eliminated (with sfield[9] in BB #5).
+      DEF_SGET_SPUT_V0(6u, Instruction::SPUT, 9u),  // Eliminated (with sfield[8] in BB #4).
   };
   static const bool expected_ignore_clinit_check[] = {
       false, true,          // Unresolved: sfield[10], method[2]
@@ -317,7 +423,7 @@
   };
 
   PrepareSFields(sfields);
-  PrepareBasicBlocks(bbs);
+  PrepareDiamond();
   PrepareMIRs(mirs);
   PerformClassInitCheckElimination();
   ASSERT_EQ(arraysize(expected_ignore_clinit_check), mir_count_);
@@ -332,26 +438,18 @@
       { 0u, 1u, 0u, 0u },
       { 1u, 1u, 1u, 1u },
   };
-  static const BBDef bbs[] = {
-      DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
-      DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
-      DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(5)),
-      DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),
-      DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 4), DEF_PRED2(3, 4)),  // "taken" loops to self.
-      DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(4)),
-  };
   static const MIRDef mirs[] = {
-      DEF_MIR(Instruction::SGET, 3u, 0u),
-      DEF_MIR(Instruction::SGET, 4u, 1u),
-      DEF_MIR(Instruction::SGET, 5u, 0u),  // Eliminated.
-      DEF_MIR(Instruction::SGET, 5u, 1u),  // Eliminated.
+      DEF_SGET_SPUT_V0(3u, Instruction::SGET, 0u),
+      DEF_SGET_SPUT_V0(4u, Instruction::SGET, 1u),
+      DEF_SGET_SPUT_V0(5u, Instruction::SGET, 0u),  // Eliminated.
+      DEF_SGET_SPUT_V0(5u, Instruction::SGET, 1u),  // Eliminated.
   };
   static const bool expected_ignore_clinit_check[] = {
       false, false, true, true
   };
 
   PrepareSFields(sfields);
-  PrepareBasicBlocks(bbs);
+  PrepareLoop();
   PrepareMIRs(mirs);
   PerformClassInitCheckElimination();
   ASSERT_EQ(arraysize(expected_ignore_clinit_check), mir_count_);
@@ -368,42 +466,24 @@
       { 2u, 1u, 2u, 2u },
       { 3u, 1u, 3u, 3u },
   };
-  static const BBDef bbs[] = {
-      DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
-      DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
-      DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
-      DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),     // The top.
-      DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)),     // The throwing insn.
-      DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)),     // Catch handler.
-      DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED2(4, 5)),  // The merged block.
-  };
   static const MIRDef mirs[] = {
-      DEF_MIR(Instruction::SGET, 3u, 0u),  // Before the exception edge.
-      DEF_MIR(Instruction::SGET, 3u, 1u),  // Before the exception edge.
-      DEF_MIR(Instruction::SGET, 4u, 2u),  // After the exception edge.
-      DEF_MIR(Instruction::SGET, 4u, 3u),  // After the exception edge.
-      DEF_MIR(Instruction::SGET, 5u, 0u),  // In catch handler; class init check eliminated.
-      DEF_MIR(Instruction::SGET, 5u, 2u),  // In catch handler; class init check not eliminated.
-      DEF_MIR(Instruction::SGET, 6u, 0u),  // Class init check eliminated.
-      DEF_MIR(Instruction::SGET, 6u, 1u),  // Class init check eliminated.
-      DEF_MIR(Instruction::SGET, 6u, 2u),  // Class init check eliminated.
-      DEF_MIR(Instruction::SGET, 6u, 3u),  // Class init check not eliminated.
+      DEF_SGET_SPUT_V0(3u, Instruction::SGET, 0u),  // Before the exception edge.
+      DEF_SGET_SPUT_V0(3u, Instruction::SGET, 1u),  // Before the exception edge.
+      DEF_SGET_SPUT_V0(4u, Instruction::SGET, 2u),  // After the exception edge.
+      DEF_SGET_SPUT_V0(4u, Instruction::SGET, 3u),  // After the exception edge.
+      DEF_SGET_SPUT_V0(5u, Instruction::SGET, 0u),  // In catch handler; clinit check eliminated.
+      DEF_SGET_SPUT_V0(5u, Instruction::SGET, 2u),  // In catch handler; clinit check not eliminated.
+      DEF_SGET_SPUT_V0(6u, Instruction::SGET, 0u),  // Class init check eliminated.
+      DEF_SGET_SPUT_V0(6u, Instruction::SGET, 1u),  // Class init check eliminated.
+      DEF_SGET_SPUT_V0(6u, Instruction::SGET, 2u),  // Class init check eliminated.
+      DEF_SGET_SPUT_V0(6u, Instruction::SGET, 3u),  // Class init check not eliminated.
   };
   static const bool expected_ignore_clinit_check[] = {
       false, false, false, false, true, false, true, true, true, false
   };
 
   PrepareSFields(sfields);
-  PrepareBasicBlocks(bbs);
-  BasicBlock* catch_handler = cu_.mir_graph->GetBasicBlock(5u);
-  catch_handler->catch_entry = true;
-  // Add successor block info to the check block.
-  BasicBlock* check_bb = cu_.mir_graph->GetBasicBlock(3u);
-  check_bb->successor_block_list_type = kCatch;
-  SuccessorBlockInfo* successor_block_info = reinterpret_cast<SuccessorBlockInfo*>
-      (cu_.arena.Alloc(sizeof(SuccessorBlockInfo), kArenaAllocSuccessor));
-  successor_block_info->block = catch_handler->id;
-  check_bb->successor_blocks.push_back(successor_block_info);
+  PrepareCatch();
   PrepareMIRs(mirs);
   PerformClassInitCheckElimination();
   ASSERT_EQ(arraysize(expected_ignore_clinit_check), mir_count_);
@@ -413,4 +493,189 @@
   }
 }
 
+#define DEF_IGET_IPUT(bb, opcode, vA, vB, field_info) \
+    { bb, opcode, field_info, vA, vB, 0u }
+#define DEF_AGET_APUT(bb, opcode, vA, vB, vC) \
+    { bb, opcode, 0u, vA, vB, vC }
+#define DEF_INVOKE(bb, opcode, vC) \
+    { bb, opcode, 0u, 0u, 0u, vC }
+#define DEF_OTHER1(bb, opcode, vA) \
+    { bb, opcode, 0u, vA, 0u, 0u }
+#define DEF_OTHER2(bb, opcode, vA, vB) \
+    { bb, opcode, 0u, vA, vB, 0u }
+
+TEST_F(NullCheckEliminationTest, SingleBlock) {
+  static const IFieldDef ifields[] = {
+      { 0u, 1u, 0u, 0u },
+      { 1u, 1u, 0u, 1u },
+      { 2u, 1u, 0u, 2u },  // Object.
+  };
+  static const MIRDef mirs[] = {
+      DEF_IGET_IPUT(3u, Instruction::IGET_OBJECT, 0u, 100u, 2u),
+      DEF_IGET_IPUT(3u, Instruction::IGET, 1u, 0u, 1u),
+      DEF_IGET_IPUT(3u, Instruction::IGET_OBJECT, 2u, 100u, 2u),  // Differs from 0u (no LVN here).
+      DEF_IGET_IPUT(3u, Instruction::IGET, 3u, 2u, 1u),
+      DEF_IGET_IPUT(3u, Instruction::IGET, 4u, 101u, 0u),
+      DEF_IGET_IPUT(3u, Instruction::IGET, 5u, 102u, 0u),
+      DEF_IGET_IPUT(3u, Instruction::IGET, 6u, 103u, 0u),
+      DEF_IGET_IPUT(3u, Instruction::IGET, 7u, 103u, 1u),
+      DEF_IGET_IPUT(3u, Instruction::IPUT, 8u, 104u, 0u),
+      DEF_IGET_IPUT(3u, Instruction::IPUT, 9u, 104u, 1u),
+      DEF_IGET_IPUT(3u, Instruction::IGET, 10u, 105u, 0u),
+      DEF_IGET_IPUT(3u, Instruction::IPUT, 11u, 105u, 1u),
+      DEF_IGET_IPUT(3u, Instruction::IPUT, 12u, 106u, 0u),
+      DEF_IGET_IPUT(3u, Instruction::IGET, 13u, 106u, 1u),
+      DEF_INVOKE(3u, Instruction::INVOKE_DIRECT, 107),
+      DEF_IGET_IPUT(3u, Instruction::IGET, 15u, 107u, 1u),
+      DEF_IGET_IPUT(3u, Instruction::IGET, 16u, 108u, 0u),
+      DEF_INVOKE(3u, Instruction::INVOKE_DIRECT, 108),
+      DEF_AGET_APUT(3u, Instruction::AGET, 18u, 109u, 110u),
+      DEF_AGET_APUT(3u, Instruction::APUT, 19u, 109u, 111u),
+      DEF_OTHER2(3u, Instruction::ARRAY_LENGTH, 20u, 112u),
+      DEF_AGET_APUT(3u, Instruction::AGET, 21u, 112u, 113u),
+      DEF_OTHER1(3u, Instruction::MONITOR_ENTER, 114u),
+      DEF_OTHER1(3u, Instruction::MONITOR_EXIT, 114u),
+  };
+  static const bool expected_ignore_null_check[] = {
+      false, false, true, false /* Not doing LVN. */,
+      false, true /* Set before running NCE. */,
+      false, true,  // IGET, IGET
+      false, true,  // IPUT, IPUT
+      false, true,  // IGET, IPUT
+      false, true,  // IPUT, IGET
+      false, true,  // INVOKE, IGET
+      false, true,  // IGET, INVOKE
+      false, true,  // AGET, APUT
+      false, true,  // ARRAY_LENGTH, AGET
+      false, true,  // MONITOR_ENTER, MONITOR_EXIT
+  };
+
+  PrepareIFields(ifields);
+  PrepareSingleBlock();
+  PrepareMIRs(mirs);
+
+  // Mark IGET 5u as null-checked to test that NCE doesn't clear this flag.
+  mirs_[5u].optimization_flags |= MIR_IGNORE_NULL_CHECK;
+
+  PerformNullCheckElimination();
+  ASSERT_EQ(arraysize(expected_ignore_null_check), mir_count_);
+  for (size_t i = 0u; i != arraysize(mirs); ++i) {
+    EXPECT_EQ(expected_ignore_null_check[i],
+              (mirs_[i].optimization_flags & MIR_IGNORE_NULL_CHECK) != 0) << i;
+  }
+}
+
+TEST_F(NullCheckEliminationTest, Diamond) {
+  static const IFieldDef ifields[] = {
+      { 0u, 1u, 0u, 0u },
+      { 1u, 1u, 0u, 1u },
+      { 2u, 1u, 0u, 2u },  // int[].
+  };
+  static const MIRDef mirs[] = {
+      // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks.
+      DEF_IGET_IPUT(3u, Instruction::IPUT, 0u, 100u, 0u),
+      DEF_IGET_IPUT(6u, Instruction::IGET, 1u, 100u, 1u),  // Eliminated (BB #3 dominates #6).
+      DEF_IGET_IPUT(3u, Instruction::IGET, 2u, 101u, 0u),
+      DEF_IGET_IPUT(4u, Instruction::IPUT, 3u, 101u, 0u),  // Eliminated (BB #3 dominates #4).
+      DEF_IGET_IPUT(3u, Instruction::IGET, 4u, 102u, 0u),
+      DEF_IGET_IPUT(5u, Instruction::IPUT, 5u, 102u, 1u),  // Eliminated (BB #3 dominates #5).
+      DEF_IGET_IPUT(4u, Instruction::IPUT, 6u, 103u, 0u),
+      DEF_IGET_IPUT(6u, Instruction::IPUT, 7u, 103u, 1u),  // Not eliminated (going through BB #5).
+      DEF_IGET_IPUT(5u, Instruction::IGET, 8u, 104u, 1u),
+      DEF_IGET_IPUT(6u, Instruction::IGET, 9u, 104u, 0u),  // Not eliminated (going through BB #4).
+      DEF_INVOKE(4u, Instruction::INVOKE_DIRECT, 105u),
+      DEF_IGET_IPUT(5u, Instruction::IGET, 11u, 105u, 1u),
+      DEF_IGET_IPUT(6u, Instruction::IPUT, 12u, 105u, 0u),  // Eliminated.
+      DEF_IGET_IPUT(3u, Instruction::IGET_OBJECT, 13u, 106u, 2u),
+      DEF_OTHER1(3u, Instruction::IF_EQZ, 13u),            // Last insn in the BB #3.
+      DEF_OTHER2(5u, Instruction::NEW_ARRAY, 13u, 107u),
+      DEF_AGET_APUT(6u, Instruction::AGET, 16u, 13u, 108u),  // Eliminated.
+  };
+  static const bool expected_ignore_null_check[] = {
+      false, true,   // BB #3 IPUT, BB #6 IGET
+      false, true,   // BB #3 IGET, BB #4 IPUT
+      false, true,   // BB #3 IGET, BB #5 IPUT
+      false, false,  // BB #4 IPUT, BB #6 IPUT
+      false, false,  // BB #5 IGET, BB #6 IGET
+      false, false, true,  // BB #4 INVOKE, BB #5 IGET, BB #6 IPUT
+      false, false,  // BB #3 IGET_OBJECT & IF_EQZ
+      false, true,   // BB #5 NEW_ARRAY, BB #6 AGET
+  };
+
+  PrepareIFields(ifields);
+  PrepareDiamond();
+  PrepareMIRs(mirs);
+  PerformNullCheckElimination();
+  ASSERT_EQ(arraysize(expected_ignore_null_check), mir_count_);
+  for (size_t i = 0u; i != arraysize(mirs); ++i) {
+    EXPECT_EQ(expected_ignore_null_check[i],
+              (mirs_[i].optimization_flags & MIR_IGNORE_NULL_CHECK) != 0) << i;
+  }
+}
+
+TEST_F(NullCheckEliminationTest, Loop) {
+  static const IFieldDef ifields[] = {
+      { 0u, 1u, 0u, 0u },
+      { 1u, 1u, 1u, 1u },
+  };
+  static const MIRDef mirs[] = {
+      DEF_IGET_IPUT(3u, Instruction::IGET, 0u, 100u, 0u),
+      DEF_IGET_IPUT(4u, Instruction::IGET, 1u, 101u, 0u),
+      DEF_IGET_IPUT(5u, Instruction::IGET, 2u, 100u, 1u),  // Eliminated.
+      DEF_IGET_IPUT(5u, Instruction::IGET, 3u, 101u, 1u),  // Eliminated.
+      DEF_IGET_IPUT(3u, Instruction::IGET, 4u, 102u, 0u),
+      DEF_IGET_IPUT(4u, Instruction::IGET, 5u, 102u, 1u),  // Not eliminated (MOVE_OBJECT_16).
+      DEF_OTHER2(4u, Instruction::MOVE_OBJECT_16, 102u, 103u),
+  };
+  static const bool expected_ignore_null_check[] = {
+      false, false, true, true,
+      false, false, false,
+  };
+
+  PrepareIFields(ifields);
+  PrepareLoop();
+  PrepareMIRs(mirs);
+  PerformNullCheckElimination();
+  ASSERT_EQ(arraysize(expected_ignore_null_check), mir_count_);
+  for (size_t i = 0u; i != arraysize(mirs); ++i) {
+    EXPECT_EQ(expected_ignore_null_check[i],
+              (mirs_[i].optimization_flags & MIR_IGNORE_NULL_CHECK) != 0) << i;
+  }
+}
+
+TEST_F(NullCheckEliminationTest, Catch) {
+  static const IFieldDef ifields[] = {
+      { 0u, 1u, 0u, 0u },
+      { 1u, 1u, 1u, 1u },
+  };
+  static const MIRDef mirs[] = {
+      DEF_IGET_IPUT(3u, Instruction::IGET, 0u, 100u, 0u),  // Before the exception edge.
+      DEF_IGET_IPUT(3u, Instruction::IGET, 1u, 101u, 0u),  // Before the exception edge.
+      DEF_IGET_IPUT(4u, Instruction::IGET, 2u, 102u, 0u),  // After the exception edge.
+      DEF_IGET_IPUT(4u, Instruction::IGET, 3u, 103u, 0u),  // After the exception edge.
+      DEF_IGET_IPUT(5u, Instruction::IGET, 4u, 100u, 1u),  // In catch handler; eliminated.
+      DEF_IGET_IPUT(5u, Instruction::IGET, 5u, 102u, 1u),  // In catch handler; not eliminated.
+      DEF_IGET_IPUT(6u, Instruction::IGET, 6u, 100u, 0u),  // Null check eliminated.
+      DEF_IGET_IPUT(6u, Instruction::IGET, 6u, 101u, 1u),  // Null check eliminated.
+      DEF_IGET_IPUT(6u, Instruction::IGET, 6u, 102u, 0u),  // Null check eliminated.
+      DEF_IGET_IPUT(6u, Instruction::IGET, 6u, 103u, 1u),  // Null check not eliminated.
+  };
+  static const bool expected_ignore_null_check[] = {
+      false, false, false, false, true, false, true, true, true, false
+  };
+
+  PrepareIFields(ifields);
+  PrepareCatch();
+  PrepareMIRs(mirs);
+  PerformNullCheckElimination();
+  ASSERT_EQ(arraysize(expected_ignore_null_check), mir_count_);
+  for (size_t i = 0u; i != arraysize(mirs); ++i) {
+    EXPECT_EQ(expected_ignore_null_check[i],
+              (mirs_[i].optimization_flags & MIR_IGNORE_NULL_CHECK) != 0) << i;
+  }
+}
+
+// Undefine MIR_DEF for null check elimination.
+#undef MIR_DEF
+
 }  // namespace art
diff --git a/compiler/dex/pass.h b/compiler/dex/pass.h
index c377426..e349eed 100644
--- a/compiler/dex/pass.h
+++ b/compiler/dex/pass.h
@@ -85,6 +85,9 @@
     // Unused parameter.
     UNUSED(data);
 
+    // Passes that do all their work in Start() or End() should not allow useless node iteration.
+    DCHECK(false) << "Unsupported default Worker() used for " << GetName();
+
     // BasicBlock did not change.
     return false;
   }
diff --git a/compiler/dex/pass_driver_me.h b/compiler/dex/pass_driver_me.h
index 537ceb6..7bfaf82 100644
--- a/compiler/dex/pass_driver_me.h
+++ b/compiler/dex/pass_driver_me.h
@@ -67,9 +67,6 @@
       case kTopologicalSortTraversal:
         DoWalkBasicBlocks<TopologicalSortIterator>(&pass_me_data_holder_, me_pass);
         break;
-      case kRepeatingTopologicalSortTraversal:
-        DoWalkBasicBlocks<RepeatingTopologicalSortIterator>(&pass_me_data_holder_, me_pass);
-        break;
       case kLoopRepeatingTopologicalSortTraversal:
         DoWalkBasicBlocks<LoopRepeatingTopologicalSortIterator>(&pass_me_data_holder_, me_pass);
         break;
diff --git a/compiler/dex/pass_driver_me_opts.cc b/compiler/dex/pass_driver_me_opts.cc
index cd3ffd4..a2bf8b4 100644
--- a/compiler/dex/pass_driver_me_opts.cc
+++ b/compiler/dex/pass_driver_me_opts.cc
@@ -20,6 +20,7 @@
 #include "dataflow_iterator.h"
 #include "dataflow_iterator-inl.h"
 #include "pass_driver_me_opts.h"
+#include "post_opt_passes.h"
 
 namespace art {
 
@@ -35,13 +36,15 @@
 const Pass* const PassDriver<PassDriverMEOpts>::g_passes[] = {
   GetPassInstance<CacheFieldLoweringInfo>(),
   GetPassInstance<CacheMethodLoweringInfo>(),
-  GetPassInstance<SpecialMethodInliner>(),
-  GetPassInstance<CodeLayout>(),
-  GetPassInstance<NullCheckElimination>(),
-  GetPassInstance<TypeInference>(),
+  GetPassInstance<CalculatePredecessors>(),
+  GetPassInstance<DFSOrders>(),
   GetPassInstance<ClassInitCheckElimination>(),
-  GetPassInstance<GlobalValueNumberingPass>(),
+  GetPassInstance<SpecialMethodInliner>(),
+  GetPassInstance<NullCheckElimination>(),
   GetPassInstance<BBCombine>(),
+  GetPassInstance<CodeLayout>(),
+  GetPassInstance<TypeInference>(),
+  GetPassInstance<GlobalValueNumberingPass>(),
   GetPassInstance<BBOptimizations>(),
 };
 
diff --git a/compiler/dex/pass_driver_me_post_opt.cc b/compiler/dex/pass_driver_me_post_opt.cc
index 4acab6c..e6238e9 100644
--- a/compiler/dex/pass_driver_me_post_opt.cc
+++ b/compiler/dex/pass_driver_me_post_opt.cc
@@ -33,7 +33,6 @@
 const Pass* const PassDriver<PassDriverMEPostOpt>::g_passes[] = {
   GetPassInstance<InitializeData>(),
   GetPassInstance<ClearPhiInstructions>(),
-  GetPassInstance<CalculatePredecessors>(),
   GetPassInstance<DFSOrders>(),
   GetPassInstance<BuildDomination>(),
   GetPassInstance<TopologicalSortOrders>(),
diff --git a/compiler/dex/pass_me.h b/compiler/dex/pass_me.h
index 8242cb8..2f3c8b2 100644
--- a/compiler/dex/pass_me.h
+++ b/compiler/dex/pass_me.h
@@ -55,7 +55,6 @@
   kRepeatingReversePostOrderDFSTraversal,  /**< @brief Depth-First-Search / Repeating Reverse Post-Order. */
   kPostOrderDOMTraversal,                  /**< @brief Dominator tree / Post-Order. */
   kTopologicalSortTraversal,               /**< @brief Topological Order traversal. */
-  kRepeatingTopologicalSortTraversal,      /**< @brief Repeating Topological Order traversal. */
   kLoopRepeatingTopologicalSortTraversal,  /**< @brief Loop-repeating Topological Order traversal. */
   kNoNodes,                                /**< @brief Skip BasicBlock traversal. */
 };
diff --git a/compiler/dex/post_opt_passes.h b/compiler/dex/post_opt_passes.h
index e7805ba..7b84ba8 100644
--- a/compiler/dex/post_opt_passes.h
+++ b/compiler/dex/post_opt_passes.h
@@ -30,7 +30,7 @@
  */
 class InitializeData : public PassME {
  public:
-  InitializeData() : PassME("InitializeData") {
+  InitializeData() : PassME("InitializeData", kNoNodes) {
   }
 
   void Start(PassDataHolder* data) const {
@@ -76,7 +76,7 @@
  */
 class CalculatePredecessors : public PassME {
  public:
-  CalculatePredecessors() : PassME("CalculatePredecessors") {
+  CalculatePredecessors() : PassME("CalculatePredecessors", kNoNodes) {
   }
 
   void Start(PassDataHolder* data) const;
@@ -88,7 +88,14 @@
  */
 class DFSOrders : public PassME {
  public:
-  DFSOrders() : PassME("DFSOrders") {
+  DFSOrders() : PassME("DFSOrders", kNoNodes) {
+  }
+
+  bool Gate(const PassDataHolder* data) const {
+    DCHECK(data != nullptr);
+    CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit;
+    DCHECK(c_unit != nullptr);
+    return !c_unit->mir_graph->DfsOrdersUpToDate();
   }
 
   void Start(PassDataHolder* data) const {
@@ -105,7 +112,7 @@
  */
 class BuildDomination : public PassME {
  public:
-  BuildDomination() : PassME("BuildDomination") {
+  BuildDomination() : PassME("BuildDomination", kNoNodes) {
   }
 
   void Start(PassDataHolder* data) const {
@@ -133,7 +140,7 @@
  */
 class TopologicalSortOrders : public PassME {
  public:
-  TopologicalSortOrders() : PassME("TopologicalSortOrders") {
+  TopologicalSortOrders() : PassME("TopologicalSortOrders", kNoNodes) {
   }
 
   void Start(PassDataHolder* data) const {
@@ -150,7 +157,7 @@
  */
 class DefBlockMatrix : public PassME {
  public:
-  DefBlockMatrix() : PassME("DefBlockMatrix") {
+  DefBlockMatrix() : PassME("DefBlockMatrix", kNoNodes) {
   }
 
   void Start(PassDataHolder* data) const {
@@ -167,7 +174,7 @@
  */
 class CreatePhiNodes : public PassME {
  public:
-  CreatePhiNodes() : PassME("CreatePhiNodes") {
+  CreatePhiNodes() : PassME("CreatePhiNodes", kNoNodes) {
   }
 
   void Start(PassDataHolder* data) const {
@@ -185,7 +192,7 @@
 
 class ClearVisitedFlag : public PassME {
  public:
-  ClearVisitedFlag() : PassME("ClearVisitedFlag") {
+  ClearVisitedFlag() : PassME("ClearVisitedFlag", kNoNodes) {
   }
 
   void Start(PassDataHolder* data) const {
@@ -202,7 +209,7 @@
  */
 class SSAConversion : public PassME {
  public:
-  SSAConversion() : PassME("SSAConversion") {
+  SSAConversion() : PassME("SSAConversion", kNoNodes) {
   }
 
   void Start(PassDataHolder* data) const {
@@ -241,7 +248,7 @@
  */
 class PerformInitRegLocations : public PassME {
  public:
-  PerformInitRegLocations() : PassME("PerformInitRegLocation") {
+  PerformInitRegLocations() : PassME("PerformInitRegLocation", kNoNodes) {
   }
 
   void Start(PassDataHolder* data) const {
@@ -286,7 +293,7 @@
  */
 class FreeData : public PassME {
  public:
-  FreeData() : PassME("FreeData") {
+  FreeData() : PassME("FreeData", kNoNodes) {
   }
 
   void End(PassDataHolder* data) const {
diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc
index e833c9a..09acf4c 100644
--- a/compiler/dex/quick/arm/utility_arm.cc
+++ b/compiler/dex/quick/arm/utility_arm.cc
@@ -969,9 +969,9 @@
     size = k32;
   }
   LIR* load;
-  if (UNLIKELY(is_volatile == kVolatile &&
-               (size == k64 || size == kDouble) &&
-               !cu_->compiler_driver->GetInstructionSetFeatures().HasLpae())) {
+  if (is_volatile == kVolatile && (size == k64 || size == kDouble) &&
+      !cu_->compiler_driver->GetInstructionSetFeatures()->
+          AsArmInstructionSetFeatures()->HasLpae()) {
     // Only 64-bit load needs special handling.
     // If the cpu supports LPAE, aligned LDRD is atomic - fall through to LoadBaseDisp().
     DCHECK(!r_dest.IsFloat());  // See RegClassForFieldLoadSave().
@@ -1093,9 +1093,9 @@
   }
 
   LIR* store;
-  if (UNLIKELY(is_volatile == kVolatile &&
-               (size == k64 || size == kDouble) &&
-               !cu_->compiler_driver->GetInstructionSetFeatures().HasLpae())) {
+  if (is_volatile == kVolatile && (size == k64 || size == kDouble) &&
+      !cu_->compiler_driver->GetInstructionSetFeatures()->
+          AsArmInstructionSetFeatures()->HasLpae()) {
     // Only 64-bit store needs special handling.
     // If the cpu supports LPAE, aligned STRD is atomic - fall through to StoreBaseDisp().
     // Use STREXD for the atomic store. (Expect displacement > 0, don't optimize for == 0.)
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 12ca065..a33d15f 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -1606,7 +1606,8 @@
       rl_result = GenDivRem(rl_dest, rl_src1.reg, rl_src2.reg, op == kOpDiv);
       done = true;
     } else if (cu_->instruction_set == kThumb2) {
-      if (cu_->GetInstructionSetFeatures().HasDivideInstruction()) {
+      if (cu_->GetInstructionSetFeatures()->AsArmInstructionSetFeatures()->
+              HasDivideInstruction()) {
         // Use ARM SDIV instruction for division.  For remainder we also need to
         // calculate using a MUL and subtract.
         rl_src1 = LoadValue(rl_src1, kCoreReg);
@@ -1875,7 +1876,8 @@
         rl_result = GenDivRemLit(rl_dest, rl_src, lit, is_div);
         done = true;
       } else if (cu_->instruction_set == kThumb2) {
-        if (cu_->GetInstructionSetFeatures().HasDivideInstruction()) {
+        if (cu_->GetInstructionSetFeatures()->AsArmInstructionSetFeatures()->
+                HasDivideInstruction()) {
           // Use ARM SDIV instruction for division.  For remainder we also need to
           // calculate using a MUL and subtract.
           rl_src = LoadValue(rl_src, kCoreReg);
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 07034cb..acf5599 100755
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -858,6 +858,11 @@
     RegLocation rl_dest = InlineTargetWide(info);
     int res_vreg, src1_vreg, src2_vreg;
 
+    if (rl_dest.s_reg_low == INVALID_SREG) {
+      // Result is unused, the code is dead. Inlining successful, no code generated.
+      return true;
+    }
+
     /*
      * If the result register is the same as the second element, then we
      * need to be careful. The reason is that the first copy will
diff --git a/compiler/dex/ssa_transformation.cc b/compiler/dex/ssa_transformation.cc
index 4388041..412f85d 100644
--- a/compiler/dex/ssa_transformation.cc
+++ b/compiler/dex/ssa_transformation.cc
@@ -66,8 +66,9 @@
 }
 
 void MIRGraph::RecordDFSOrders(BasicBlock* block) {
-  DCHECK(temp_scoped_alloc_.get() != nullptr);
-  ScopedArenaVector<BasicBlock*> succ(temp_scoped_alloc_->Adapter());
+  ScopedArenaAllocator allocator(&cu_->arena_stack);
+  ScopedArenaVector<BasicBlock*> succ(allocator.Adapter());
+  succ.reserve(GetNumBlocks());
   MarkPreOrder(block);
   succ.push_back(block);
   while (!succ.empty()) {
@@ -107,10 +108,11 @@
     AllNodesIterator iter(this);
     for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) {
       if (!bb->visited) {
-        bb->Hide(cu_);
+        bb->Hide(this);
       }
     }
   }
+  dfs_orders_up_to_date_ = true;
 }
 
 /*
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 4d5d253..3325568 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -243,8 +243,14 @@
     CHECK(referrer_class->GetDexCache()->GetResolvedMethod(target_method->dex_method_index) ==
         resolved_method) << PrettyMethod(resolved_method);
     int stats_flags = kFlagMethodResolved;
-    GetCodeAndMethodForDirectCall(invoke_type, kDirect, false, referrer_class, resolved_method,
-                                  &stats_flags, target_method, direct_code, direct_method);
+    GetCodeAndMethodForDirectCall(/*out*/invoke_type,
+                                  kDirect,  // Sharp type
+                                  false,    // The dex cache is guaranteed to be available
+                                  referrer_class, resolved_method,
+                                  /*out*/&stats_flags,
+                                  target_method,
+                                  /*out*/direct_code,
+                                  /*out*/direct_method);
     DCHECK_NE(*invoke_type, kSuper) << PrettyMethod(resolved_method);
     if (*invoke_type == kDirect) {
       stats_flags |= kFlagsMethodResolvedVirtualMadeDirect;
@@ -273,8 +279,14 @@
     CHECK(called_method != NULL);
     CHECK(!called_method->IsAbstract());
     int stats_flags = kFlagMethodResolved;
-    GetCodeAndMethodForDirectCall(invoke_type, kDirect, true, referrer_class, called_method,
-                                  &stats_flags, target_method, direct_code, direct_method);
+    GetCodeAndMethodForDirectCall(/*out*/invoke_type,
+                                  kDirect,  // Sharp type
+                                  true,     // The dex cache may not be available
+                                  referrer_class, called_method,
+                                  /*out*/&stats_flags,
+                                  target_method,
+                                  /*out*/direct_code,
+                                  /*out*/direct_method);
     DCHECK_NE(*invoke_type, kSuper);
     if (*invoke_type == kDirect) {
       stats_flags |= kFlagsMethodResolvedPreciseTypeDevirtualization;
@@ -289,8 +301,14 @@
 
   // Sharpening failed so generate a regular resolved method dispatch.
   int stats_flags = kFlagMethodResolved;
-  GetCodeAndMethodForDirectCall(invoke_type, *invoke_type, false, referrer_class, resolved_method,
-                                &stats_flags, target_method, direct_code, direct_method);
+  GetCodeAndMethodForDirectCall(/*out*/invoke_type,
+                                *invoke_type,  // Sharp type
+                                false,         // The dex cache is guaranteed to be available
+                                referrer_class, resolved_method,
+                                /*out*/&stats_flags,
+                                target_method,
+                                /*out*/direct_code,
+                                /*out*/direct_method);
   return stats_flags;
 }
 
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index fb648fc..a60c5bc 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -329,10 +329,10 @@
                                DexFileToMethodInlinerMap* method_inliner_map,
                                Compiler::Kind compiler_kind,
                                InstructionSet instruction_set,
-                               InstructionSetFeatures instruction_set_features,
+                               const InstructionSetFeatures* instruction_set_features,
                                bool image, std::set<std::string>* image_classes, size_t thread_count,
                                bool dump_stats, bool dump_passes, CumulativeLogger* timer,
-                               std::string profile_file)
+                               const std::string& profile_file)
     : profile_present_(false), compiler_options_(compiler_options),
       verification_results_(verification_results),
       method_inliner_map_(method_inliner_map),
@@ -347,15 +347,11 @@
       image_(image),
       image_classes_(image_classes),
       thread_count_(thread_count),
-      start_ns_(0),
       stats_(new AOTCompilationStats),
       dump_stats_(dump_stats),
       dump_passes_(dump_passes),
       timings_logger_(timer),
-      compiler_library_(nullptr),
       compiler_context_(nullptr),
-      compiler_enable_auto_elf_loading_(nullptr),
-      compiler_get_method_code_addr_(nullptr),
       support_boot_image_fixup_(instruction_set != kMips),
       dedupe_code_("dedupe code"),
       dedupe_src_mapping_table_("dedupe source mapping table"),
@@ -920,6 +916,10 @@
   if (resolved_class == nullptr) {
     return false;
   }
+  if (GetCompilerOptions().GetCompilePic()) {
+    // Do not allow a direct class pointer to be used when compiling for position-independent
+    return false;
+  }
   *out_is_finalizable = resolved_class->IsFinalizable();
   const bool compiling_boot = Runtime::Current()->GetHeap()->IsCompilingBoot();
   const bool support_boot_image_fixup = GetSupportBootImageFixup();
@@ -1112,7 +1112,7 @@
 
 void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType sharp_type,
                                                    bool no_guarantee_of_dex_cache_entry,
-                                                   mirror::Class* referrer_class,
+                                                   const mirror::Class* referrer_class,
                                                    mirror::ArtMethod* method,
                                                    int* stats_flags,
                                                    MethodReference* target_method,
@@ -1124,7 +1124,7 @@
   // invoked, so this can be passed to the out-of-line runtime support code.
   *direct_code = 0;
   *direct_method = 0;
-  bool use_dex_cache = false;
+  bool use_dex_cache = GetCompilerOptions().GetCompilePic();  // Off by default
   const bool compiling_boot = Runtime::Current()->GetHeap()->IsCompilingBoot();
   // TODO This is somewhat hacky. We should refactor all of this invoke codepath.
   const bool force_relocations = (compiling_boot ||
@@ -1139,7 +1139,7 @@
       return;
     }
     // TODO: support patching on all architectures.
-    use_dex_cache = force_relocations && !support_boot_image_fixup_;
+    use_dex_cache = use_dex_cache || (force_relocations && !support_boot_image_fixup_);
   }
   bool method_code_in_boot = (method->GetDeclaringClass()->GetClassLoader() == nullptr);
   if (!use_dex_cache) {
@@ -1951,6 +1951,19 @@
   context.ForAll(0, dex_file.NumClassDefs(), CompilerDriver::CompileClass, thread_count_);
 }
 
+// Does the runtime for the InstructionSet provide an implementation returned by
+// GetQuickGenericJniStub allowing down calls that aren't compiled using a JNI compiler?
+static bool InstructionSetHasGenericJniStub(InstructionSet isa) {
+  switch (isa) {
+    case kArm:
+    case kArm64:
+    case kThumb2:
+    case kX86:
+    case kX86_64: return true;
+    default: return false;
+  }
+}
+
 void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags,
                                    InvokeType invoke_type, uint16_t class_def_idx,
                                    uint32_t method_idx, jobject class_loader,
@@ -1962,13 +1975,14 @@
   if ((access_flags & kAccNative) != 0) {
     // Are we interpreting only and have support for generic JNI down calls?
     if (!compiler_options_->IsCompilationEnabled() &&
-        (instruction_set_ == kX86_64 || instruction_set_ == kArm64)) {
+        InstructionSetHasGenericJniStub(instruction_set_)) {
       // Leaving this empty will trigger the generic JNI version
     } else {
       compiled_method = compiler_->JniCompile(access_flags, method_idx, dex_file);
       CHECK(compiled_method != nullptr);
     }
   } else if ((access_flags & kAccAbstract) != 0) {
+    // Abstract methods don't have code.
   } else {
     MethodReference method_ref(&dex_file, method_idx);
     bool compile = verification_results_->IsCandidateForCompilation(method_ref, access_flags);
@@ -2002,6 +2016,10 @@
         ++non_relative_linker_patch_count;
       }
     }
+    bool compile_pic = GetCompilerOptions().GetCompilePic();  // Off by default
+    // When compiling with PIC, there should be zero non-relative linker patches
+    CHECK(!compile_pic || non_relative_linker_patch_count == 0u);
+
     MethodReference ref(&dex_file, method_idx);
     DCHECK(GetCompiledMethod(ref) == nullptr) << PrettyMethod(method_idx, dex_file);
     {
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index c445683..0796f48 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -88,10 +88,10 @@
                           DexFileToMethodInlinerMap* method_inliner_map,
                           Compiler::Kind compiler_kind,
                           InstructionSet instruction_set,
-                          InstructionSetFeatures instruction_set_features,
+                          const InstructionSetFeatures* instruction_set_features,
                           bool image, std::set<std::string>* image_classes,
                           size_t thread_count, bool dump_stats, bool dump_passes,
-                          CumulativeLogger* timer, std::string profile_file = "");
+                          CumulativeLogger* timer, const std::string& profile_file);
 
   ~CompilerDriver();
 
@@ -115,7 +115,7 @@
     return instruction_set_;
   }
 
-  InstructionSetFeatures GetInstructionSetFeatures() const {
+  const InstructionSetFeatures* GetInstructionSetFeatures() const {
     return instruction_set_features_;
   }
 
@@ -400,11 +400,12 @@
 
  public:  // TODO make private or eliminate.
   // Compute constant code and method pointers when possible.
-  void GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType sharp_type,
+  void GetCodeAndMethodForDirectCall(/*out*/InvokeType* type,
+                                     InvokeType sharp_type,
                                      bool no_guarantee_of_dex_cache_entry,
-                                     mirror::Class* referrer_class,
+                                     const mirror::Class* referrer_class,
                                      mirror::ArtMethod* method,
-                                     int* stats_flags,
+                                     /*out*/int* stats_flags,
                                      MethodReference* target_method,
                                      uintptr_t* direct_code, uintptr_t* direct_method)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -475,7 +476,7 @@
   std::unique_ptr<Compiler> compiler_;
 
   const InstructionSet instruction_set_;
-  const InstructionSetFeatures instruction_set_features_;
+  const InstructionSetFeatures* const instruction_set_features_;
 
   // All class references that require
   mutable ReaderWriterMutex freezing_constructor_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
@@ -502,7 +503,6 @@
   std::unique_ptr<std::set<std::string>> image_classes_;
 
   size_t thread_count_;
-  uint64_t start_ns_;
 
   class AOTCompilationStats;
   std::unique_ptr<AOTCompilationStats> stats_;
@@ -515,8 +515,6 @@
   typedef void (*CompilerCallbackFn)(CompilerDriver& driver);
   typedef MutexLock* (*CompilerMutexLockFn)(CompilerDriver& driver);
 
-  void* compiler_library_;
-
   typedef void (*DexToDexCompilerFn)(CompilerDriver& driver,
                                      const DexFile::CodeItem* code_item,
                                      uint32_t access_flags, InvokeType invoke_type,
@@ -532,13 +530,6 @@
   // Arena pool used by the compiler.
   ArenaPool arena_pool_;
 
-  typedef void (*CompilerEnableAutoElfLoadingFn)(CompilerDriver& driver);
-  CompilerEnableAutoElfLoadingFn compiler_enable_auto_elf_loading_;
-
-  typedef const void* (*CompilerGetMethodCodeAddrFn)
-      (const CompilerDriver& driver, const CompiledMethod* cm, const mirror::ArtMethod* method);
-  CompilerGetMethodCodeAddrFn compiler_get_method_code_addr_;
-
   bool support_boot_image_fixup_;
 
   // DeDuplication data structures, these own the corresponding byte arrays.
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index eb3de97..fb7aeb9 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -17,9 +17,14 @@
 #ifndef ART_COMPILER_DRIVER_COMPILER_OPTIONS_H_
 #define ART_COMPILER_DRIVER_COMPILER_OPTIONS_H_
 
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+
 namespace art {
 
-class CompilerOptions {
+class CompilerOptions FINAL {
  public:
   enum CompilerFilter {
     kVerifyNone,          // Skip verification and compile nothing except JNI stubs.
@@ -28,7 +33,7 @@
     kBalanced,            // Try to get the best performance return on compilation investment.
     kSpeed,               // Maximize runtime performance.
     kEverything,          // Force compilation (Note: excludes compilation of class initializers).
-    kTime                 // Compile methods, but minimize compilation time.
+    kTime,                // Compile methods, but minimize compilation time.
   };
 
   // Guide heuristics to determine whether to compile method if profile data not available.
@@ -59,11 +64,13 @@
     include_debug_symbols_(kDefaultIncludeDebugSymbols),
     implicit_null_checks_(false),
     implicit_so_checks_(false),
-    implicit_suspend_checks_(false)
+    implicit_suspend_checks_(false),
+    compile_pic_(false),
 #ifdef ART_SEA_IR_MODE
-    , sea_ir_mode_(false)
+    sea_ir_mode_(false),
 #endif
-    {}
+    verbose_methods_(nullptr) {
+  }
 
   CompilerOptions(CompilerFilter compiler_filter,
                   size_t huge_method_threshold,
@@ -77,10 +84,12 @@
                   bool include_debug_symbols,
                   bool implicit_null_checks,
                   bool implicit_so_checks,
-                  bool implicit_suspend_checks
+                  bool implicit_suspend_checks,
+                  bool compile_pic,
 #ifdef ART_SEA_IR_MODE
-                  , bool sea_ir_mode
+                  bool sea_ir_mode,
 #endif
+                  const std::vector<std::string>* verbose_methods
                   ) :  // NOLINT(whitespace/parens)
     compiler_filter_(compiler_filter),
     huge_method_threshold_(huge_method_threshold),
@@ -94,11 +103,13 @@
     include_debug_symbols_(include_debug_symbols),
     implicit_null_checks_(implicit_null_checks),
     implicit_so_checks_(implicit_so_checks),
-    implicit_suspend_checks_(implicit_suspend_checks)
+    implicit_suspend_checks_(implicit_suspend_checks),
+    compile_pic_(compile_pic),
 #ifdef ART_SEA_IR_MODE
-    , sea_ir_mode_(sea_ir_mode)
+    sea_ir_mode_(sea_ir_mode),
 #endif
-    {}
+    verbose_methods_(verbose_methods) {
+  }
 
   CompilerFilter GetCompilerFilter() const {
     return compiler_filter_;
@@ -165,28 +176,18 @@
     return implicit_null_checks_;
   }
 
-  void SetImplicitNullChecks(bool new_val) {
-    implicit_null_checks_ = new_val;
-  }
-
   bool GetImplicitStackOverflowChecks() const {
     return implicit_so_checks_;
   }
 
-  void SetImplicitStackOverflowChecks(bool new_val) {
-    implicit_so_checks_ = new_val;
-  }
-
   bool GetImplicitSuspendChecks() const {
     return implicit_suspend_checks_;
   }
 
-  void SetImplicitSuspendChecks(bool new_val) {
-    implicit_suspend_checks_ = new_val;
-  }
-
 #ifdef ART_SEA_IR_MODE
-  bool GetSeaIrMode();
+  bool GetSeaIrMode() const {
+    return sea_ir_mode_;
+  }
 #endif
 
   bool GetGenerateGDBInformation() const {
@@ -197,24 +198,49 @@
     return include_patch_information_;
   }
 
+  // Should the code be compiled as position independent?
+  bool GetCompilePic() const {
+    return compile_pic_;
+  }
+
+  bool HasVerboseMethods() const {
+    return verbose_methods_ != nullptr && !verbose_methods_->empty();
+  }
+
+  bool IsVerboseMethod(const std::string& pretty_method) const {
+    for (const std::string& cur_method : *verbose_methods_) {
+      if (pretty_method.find(cur_method) != std::string::npos) {
+        return true;
+      }
+    }
+    return false;
+  }
+
  private:
   CompilerFilter compiler_filter_;
-  size_t huge_method_threshold_;
-  size_t large_method_threshold_;
-  size_t small_method_threshold_;
-  size_t tiny_method_threshold_;
-  size_t num_dex_methods_threshold_;
-  bool generate_gdb_information_;
-  bool include_patch_information_;
+  const size_t huge_method_threshold_;
+  const size_t large_method_threshold_;
+  const size_t small_method_threshold_;
+  const size_t tiny_method_threshold_;
+  const size_t num_dex_methods_threshold_;
+  const bool generate_gdb_information_;
+  const bool include_patch_information_;
   // When using a profile file only the top K% of the profiled samples will be compiled.
-  double top_k_profile_threshold_;
-  bool include_debug_symbols_;
-  bool implicit_null_checks_;
-  bool implicit_so_checks_;
-  bool implicit_suspend_checks_;
+  const double top_k_profile_threshold_;
+  const bool include_debug_symbols_;
+  const bool implicit_null_checks_;
+  const bool implicit_so_checks_;
+  const bool implicit_suspend_checks_;
+  const bool compile_pic_;
+
 #ifdef ART_SEA_IR_MODE
-  bool sea_ir_mode_;
+  const bool sea_ir_mode_;
 #endif
+
+  // Vector of methods to have verbose output enabled for.
+  const std::vector<std::string>* const verbose_methods_;
+
+  DISALLOW_COPY_AND_ASSIGN(CompilerOptions);
 };
 
 }  // namespace art
diff --git a/compiler/elf_writer_test.cc b/compiler/elf_writer_test.cc
index e479322..2ffbd10 100644
--- a/compiler/elf_writer_test.cc
+++ b/compiler/elf_writer_test.cc
@@ -17,6 +17,7 @@
 #include "elf_file.h"
 
 #include "base/stringprintf.h"
+#include "base/unix_file/fd_file.h"
 #include "common_compiler_test.h"
 #include "oat.h"
 #include "utils.h"
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index cf4259f..d5d487f 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -63,7 +63,7 @@
   ScratchFile oat_file(OS::CreateEmptyFile(oat_filename.c_str()));
 
   const uintptr_t requested_image_base = ART_BASE_ADDRESS;
-  ImageWriter writer(*compiler_driver_, requested_image_base);
+  std::unique_ptr<ImageWriter> writer(new ImageWriter(*compiler_driver_, requested_image_base));
   {
     {
       jobject class_loader = NULL;
@@ -83,8 +83,8 @@
       t.NewTiming("WriteElf");
       SafeMap<std::string, std::string> key_value_store;
       OatWriter oat_writer(class_linker->GetBootClassPath(), 0, 0, 0, compiler_driver_.get(),
-                           &writer, &timings, &key_value_store);
-      bool success = writer.PrepareImageAddressSpace() &&
+                           writer.get(), &timings, &key_value_store);
+      bool success = writer->PrepareImageAddressSpace() &&
           compiler_driver_->WriteElf(GetTestAndroidRoot(),
                                      !kIsTargetBuild,
                                      class_linker->GetBootClassPath(),
@@ -99,9 +99,9 @@
 
   {
     bool success_image =
-        writer.Write(image_file.GetFilename(), dup_oat->GetPath(), dup_oat->GetPath());
+        writer->Write(image_file.GetFilename(), dup_oat->GetPath(), dup_oat->GetPath());
     ASSERT_TRUE(success_image);
-    bool success_fixup = ElfWriter::Fixup(dup_oat.get(), writer.GetOatDataBegin());
+    bool success_fixup = ElfWriter::Fixup(dup_oat.get(), writer->GetOatDataBegin());
     ASSERT_TRUE(success_fixup);
   }
 
@@ -130,14 +130,18 @@
   compiler_driver_.reset();
 
   // Tear down old runtime before making a new one, clearing out misc state.
+
+  // Remove the reservation of the memory for use to load the image.
+  // Need to do this before we reset the runtime.
+  UnreserveImageSpace();
+  writer.reset(nullptr);
+
   runtime_.reset();
   java_lang_dex_file_ = NULL;
 
+  MemMap::Init();
   std::unique_ptr<const DexFile> dex(LoadExpectSingleDexFile(GetLibCoreDexFileName().c_str()));
 
-  // Remove the reservation of the memory for use to load the image.
-  UnreserveImageSpace();
-
   RuntimeOptions options;
   std::string image("-Ximage:");
   image.append(image_location.GetFilename());
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index fd7d350..0fea2a7 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -73,10 +73,10 @@
     }
     ASSERT_TRUE(method != nullptr) << method_name << " " << method_sig;
     if (check_generic_jni_) {
-      method->SetEntryPointFromQuickCompiledCode(class_linker_->GetQuickGenericJniTrampoline());
+      method->SetEntryPointFromQuickCompiledCode(class_linker_->GetRuntimeQuickGenericJniStub());
     } else {
-      if (method->GetEntryPointFromQuickCompiledCode() == nullptr ||
-          method->GetEntryPointFromQuickCompiledCode() == class_linker_->GetQuickGenericJniTrampoline()) {
+      const void* code = method->GetEntryPointFromQuickCompiledCode();
+      if (code == nullptr || class_linker_->IsQuickGenericJniStub(code)) {
         CompileMethod(method);
         ASSERT_TRUE(method->GetEntryPointFromQuickCompiledCode() != nullptr)
             << method_name << " " << method_sig;
diff --git a/compiler/jni/quick/arm64/calling_convention_arm64.cc b/compiler/jni/quick/arm64/calling_convention_arm64.cc
index b95dad2..29763a2 100644
--- a/compiler/jni/quick/arm64/calling_convention_arm64.cc
+++ b/compiler/jni/quick/arm64/calling_convention_arm64.cc
@@ -21,7 +21,7 @@
 namespace art {
 namespace arm64 {
 
-static const Register kCoreArgumentRegisters[] = {
+static const XRegister kXArgumentRegisters[] = {
   X0, X1, X2, X3, X4, X5, X6, X7
 };
 
@@ -39,11 +39,11 @@
 
 // Calling convention
 ManagedRegister Arm64ManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
-  return Arm64ManagedRegister::FromCoreRegister(X20);  // saved on entry restored on exit
+  return Arm64ManagedRegister::FromXRegister(X20);  // saved on entry restored on exit
 }
 
 ManagedRegister Arm64JniCallingConvention::InterproceduralScratchRegister() {
-  return Arm64ManagedRegister::FromCoreRegister(X20);  // saved on entry restored on exit
+  return Arm64ManagedRegister::FromXRegister(X20);  // saved on entry restored on exit
 }
 
 static ManagedRegister ReturnRegisterForShorty(const char* shorty) {
@@ -52,7 +52,7 @@
   } else if (shorty[0] == 'D') {
     return Arm64ManagedRegister::FromDRegister(D0);
   } else if (shorty[0] == 'J') {
-    return Arm64ManagedRegister::FromCoreRegister(X0);
+    return Arm64ManagedRegister::FromXRegister(X0);
   } else if (shorty[0] == 'V') {
     return Arm64ManagedRegister::NoRegister();
   } else {
@@ -75,7 +75,7 @@
 // Managed runtime calling convention
 
 ManagedRegister Arm64ManagedRuntimeCallingConvention::MethodRegister() {
-  return Arm64ManagedRegister::FromCoreRegister(X0);
+  return Arm64ManagedRegister::FromXRegister(X0);
 }
 
 bool Arm64ManagedRuntimeCallingConvention::IsCurrentParamInRegister() {
@@ -129,7 +129,7 @@
       } else {  // GP regs.
         if (gp_reg_index < 8) {
           if (IsCurrentParamALong() && (!IsCurrentParamAReference())) {
-            entry_spills_.push_back(Arm64ManagedRegister::FromCoreRegister(kCoreArgumentRegisters[gp_reg_index]));
+            entry_spills_.push_back(Arm64ManagedRegister::FromXRegister(kXArgumentRegisters[gp_reg_index]));
           } else {
             entry_spills_.push_back(Arm64ManagedRegister::FromWRegister(kWArgumentRegisters[gp_reg_index]));
           }
@@ -154,17 +154,17 @@
     : JniCallingConvention(is_static, is_synchronized, shorty, kFramePointerSize) {
   // TODO: Ugly hard code...
   // Should generate these according to the spill mask automatically.
-  callee_save_regs_.push_back(Arm64ManagedRegister::FromCoreRegister(X20));
-  callee_save_regs_.push_back(Arm64ManagedRegister::FromCoreRegister(X21));
-  callee_save_regs_.push_back(Arm64ManagedRegister::FromCoreRegister(X22));
-  callee_save_regs_.push_back(Arm64ManagedRegister::FromCoreRegister(X23));
-  callee_save_regs_.push_back(Arm64ManagedRegister::FromCoreRegister(X24));
-  callee_save_regs_.push_back(Arm64ManagedRegister::FromCoreRegister(X25));
-  callee_save_regs_.push_back(Arm64ManagedRegister::FromCoreRegister(X26));
-  callee_save_regs_.push_back(Arm64ManagedRegister::FromCoreRegister(X27));
-  callee_save_regs_.push_back(Arm64ManagedRegister::FromCoreRegister(X28));
-  callee_save_regs_.push_back(Arm64ManagedRegister::FromCoreRegister(X29));
-  callee_save_regs_.push_back(Arm64ManagedRegister::FromCoreRegister(X30));
+  callee_save_regs_.push_back(Arm64ManagedRegister::FromXRegister(X20));
+  callee_save_regs_.push_back(Arm64ManagedRegister::FromXRegister(X21));
+  callee_save_regs_.push_back(Arm64ManagedRegister::FromXRegister(X22));
+  callee_save_regs_.push_back(Arm64ManagedRegister::FromXRegister(X23));
+  callee_save_regs_.push_back(Arm64ManagedRegister::FromXRegister(X24));
+  callee_save_regs_.push_back(Arm64ManagedRegister::FromXRegister(X25));
+  callee_save_regs_.push_back(Arm64ManagedRegister::FromXRegister(X26));
+  callee_save_regs_.push_back(Arm64ManagedRegister::FromXRegister(X27));
+  callee_save_regs_.push_back(Arm64ManagedRegister::FromXRegister(X28));
+  callee_save_regs_.push_back(Arm64ManagedRegister::FromXRegister(X29));
+  callee_save_regs_.push_back(Arm64ManagedRegister::FromXRegister(X30));
 }
 
 uint32_t Arm64JniCallingConvention::CoreSpillMask() const {
@@ -232,7 +232,7 @@
     int gp_reg = itr_args_ - itr_float_and_doubles_;
     CHECK_LT(static_cast<unsigned int>(gp_reg), 8u);
     if (IsCurrentParamALong() || IsCurrentParamAReference() || IsCurrentParamJniEnv())  {
-      return Arm64ManagedRegister::FromCoreRegister(kCoreArgumentRegisters[gp_reg]);
+      return Arm64ManagedRegister::FromXRegister(kXArgumentRegisters[gp_reg]);
     } else {
       return Arm64ManagedRegister::FromWRegister(kWArgumentRegisters[gp_reg]);
     }
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index f6795ea..3c3aa02 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -176,12 +176,8 @@
   // 4. Write out the end of the quick frames.
   if (is_64_bit_target) {
     __ StoreStackPointerToThread64(Thread::TopOfManagedStackOffset<8>());
-    __ StoreImmediateToThread64(Thread::TopOfManagedStackPcOffset<8>(), 0,
-                              mr_conv->InterproceduralScratchRegister());
   } else {
     __ StoreStackPointerToThread32(Thread::TopOfManagedStackOffset<4>());
-    __ StoreImmediateToThread32(Thread::TopOfManagedStackPcOffset<4>(), 0,
-                              mr_conv->InterproceduralScratchRegister());
   }
 
   // 5. Move frame down to allow space for out going args.
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 3fcc369..847fa0d 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -44,11 +44,11 @@
         compiler_driver_->GetCompiledMethod(MethodReference(dex_file,
                                                             method->GetDexMethodIndex()));
 
-    if (compiled_method == NULL) {
-      EXPECT_TRUE(oat_method.GetQuickCode() == NULL) << PrettyMethod(method) << " "
-                                                     << oat_method.GetQuickCode();
-      EXPECT_TRUE(oat_method.GetPortableCode() == NULL) << PrettyMethod(method) << " "
-                                                        << oat_method.GetPortableCode();
+    if (compiled_method == nullptr) {
+      EXPECT_TRUE(oat_method.GetQuickCode() == nullptr) << PrettyMethod(method) << " "
+                                                        << oat_method.GetQuickCode();
+      EXPECT_TRUE(oat_method.GetPortableCode() == nullptr) << PrettyMethod(method) << " "
+                                                           << oat_method.GetPortableCode();
       EXPECT_EQ(oat_method.GetFrameSizeInBytes(), 0U);
       EXPECT_EQ(oat_method.GetCoreSpillMask(), 0U);
       EXPECT_EQ(oat_method.GetFpSpillMask(), 0U);
@@ -95,7 +95,10 @@
       : Compiler::kQuick;
   InstructionSet insn_set = kIsTargetBuild ? kThumb2 : kX86;
 
-  InstructionSetFeatures insn_features;
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> insn_features(
+      InstructionSetFeatures::FromFeatureString(insn_set, "default", &error_msg));
+  ASSERT_TRUE(insn_features.get() != nullptr) << error_msg;
   compiler_options_.reset(new CompilerOptions);
   verification_results_.reset(new VerificationResults(compiler_options_.get()));
   method_inliner_map_.reset(new DexFileToMethodInlinerMap);
@@ -106,9 +109,9 @@
                                             verification_results_.get(),
                                             method_inliner_map_.get(),
                                             compiler_kind, insn_set,
-                                            insn_features, false, NULL, 2, true, true,
-                                            timer_.get()));
-  jobject class_loader = NULL;
+                                            insn_features.get(), false, nullptr, 2, true, true,
+                                            timer_.get(), ""));
+  jobject class_loader = nullptr;
   if (kCompile) {
     TimingLogger timings("OatTest::WriteRead", false, false);
     compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings);
@@ -135,9 +138,8 @@
   if (kCompile) {  // OatWriter strips the code, regenerate to compare
     compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings);
   }
-  std::string error_msg;
-  std::unique_ptr<OatFile> oat_file(OatFile::Open(tmp.GetFilename(), tmp.GetFilename(), NULL, false,
-                                            &error_msg));
+  std::unique_ptr<OatFile> oat_file(OatFile::Open(tmp.GetFilename(), tmp.GetFilename(), nullptr,
+                                                  false, &error_msg));
   ASSERT_TRUE(oat_file.get() != nullptr) << error_msg;
   const OatHeader& oat_header = oat_file->GetOatHeader();
   ASSERT_TRUE(oat_header.IsValid());
@@ -157,7 +159,7 @@
     const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
     const uint8_t* class_data = dex_file->GetClassData(class_def);
     size_t num_virtual_methods = 0;
-    if (class_data != NULL) {
+    if (class_data != nullptr) {
       ClassDataItemIterator it(*dex_file, class_data);
       num_virtual_methods = it.NumVirtualMethods();
     }
@@ -193,13 +195,16 @@
 }
 
 TEST_F(OatTest, OatHeaderIsValid) {
-    InstructionSet instruction_set = kX86;
-    InstructionSetFeatures instruction_set_features;
+    InstructionSet insn_set = kX86;
+    std::string error_msg;
+    std::unique_ptr<const InstructionSetFeatures> insn_features(
+        InstructionSetFeatures::FromFeatureString(insn_set, "default", &error_msg));
+    ASSERT_TRUE(insn_features.get() != nullptr) << error_msg;
     std::vector<const DexFile*> dex_files;
     uint32_t image_file_location_oat_checksum = 0;
     uint32_t image_file_location_oat_begin = 0;
-    std::unique_ptr<OatHeader> oat_header(OatHeader::Create(instruction_set,
-                                                            instruction_set_features,
+    std::unique_ptr<OatHeader> oat_header(OatHeader::Create(insn_set,
+                                                            insn_features.get(),
                                                             &dex_files,
                                                             image_file_location_oat_checksum,
                                                             image_file_location_oat_begin,
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 5bcc65b..79cbd0e 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -171,6 +171,7 @@
 
   const uint16_t* code_ptr = code_item.insns_;
   const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_;
+  code_start_ = code_ptr;
 
   // Setup the graph with the entry block and exit block.
   graph_ = new (arena_) HGraph(arena_);
@@ -267,6 +268,13 @@
 }
 
 template<typename T>
+void HGraphBuilder::Unop_12x(const Instruction& instruction, Primitive::Type type) {
+  HInstruction* first = LoadLocal(instruction.VRegB(), type);
+  current_block_->AddInstruction(new (arena_) T(type, first));
+  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+}
+
+template<typename T>
 void HGraphBuilder::Binop_23x(const Instruction& instruction, Primitive::Type type) {
   HInstruction* first = LoadLocal(instruction.VRegB(), type);
   HInstruction* second = LoadLocal(instruction.VRegC(), type);
@@ -409,6 +417,7 @@
 
   DCHECK_EQ(argument_index, number_of_arguments);
   current_block_->AddInstruction(invoke);
+  latest_result_ = invoke;
   return true;
 }
 
@@ -496,6 +505,62 @@
   }
 }
 
+void HGraphBuilder::BuildFilledNewArray(uint32_t dex_offset,
+                                        uint32_t type_index,
+                                        uint32_t number_of_vreg_arguments,
+                                        bool is_range,
+                                        uint32_t* args,
+                                        uint32_t register_index) {
+  HInstruction* length = GetIntConstant(number_of_vreg_arguments);
+  HInstruction* object = new (arena_) HNewArray(length, dex_offset, type_index);
+  current_block_->AddInstruction(object);
+
+  const char* descriptor = dex_file_->StringByTypeIdx(type_index);
+  DCHECK_EQ(descriptor[0], '[') << descriptor;
+  char primitive = descriptor[1];
+  DCHECK(primitive == 'I'
+      || primitive == 'L'
+      || primitive == '[') << descriptor;
+  bool is_reference_array = (primitive == 'L') || (primitive == '[');
+  Primitive::Type type = is_reference_array ? Primitive::kPrimNot : Primitive::kPrimInt;
+
+  Temporaries temps(graph_, 1);
+  temps.Add(object);
+  for (size_t i = 0; i < number_of_vreg_arguments; ++i) {
+    HInstruction* value = LoadLocal(is_range ? register_index + i : args[i], type);
+    HInstruction* index = GetIntConstant(i);
+    current_block_->AddInstruction(
+        new (arena_) HArraySet(object, index, value, type, dex_offset));
+  }
+  latest_result_ = object;
+}
+
+template <typename T>
+void HGraphBuilder::BuildFillArrayData(HInstruction* object,
+                                       const T* data,
+                                       uint32_t element_count,
+                                       Primitive::Type anticipated_type,
+                                       uint32_t dex_offset) {
+  for (uint32_t i = 0; i < element_count; ++i) {
+    HInstruction* index = GetIntConstant(i);
+    HInstruction* value = GetIntConstant(data[i]);
+    current_block_->AddInstruction(new (arena_) HArraySet(
+      object, index, value, anticipated_type, dex_offset));
+  }
+}
+
+void HGraphBuilder::BuildFillWideArrayData(HInstruction* object,
+                                           const uint64_t* data,
+                                           uint32_t element_count,
+                                           uint32_t dex_offset) {
+  for (uint32_t i = 0; i < element_count; ++i) {
+    HInstruction* index = GetIntConstant(i);
+    HInstruction* value = GetLongConstant(data[i]);
+    current_block_->AddInstruction(new (arena_) HArraySet(
+      object, index, value, Primitive::kPrimLong, dex_offset));
+  }
+}
+
 void HGraphBuilder::PotentiallyAddSuspendCheck(int32_t target_offset, uint32_t dex_offset) {
   if (target_offset <= 0) {
     // Unconditionnally add a suspend check to backward branches. We can remove
@@ -678,6 +743,16 @@
       break;
     }
 
+    case Instruction::NEG_INT: {
+      Unop_12x<HNeg>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::NOT_INT: {
+      Unop_12x<HNot>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
     case Instruction::ADD_INT: {
       Binop_23x<HAdd>(instruction, Primitive::kPrimInt);
       break;
@@ -708,11 +783,41 @@
       break;
     }
 
+    case Instruction::SUB_FLOAT: {
+      Binop_23x<HSub>(instruction, Primitive::kPrimFloat);
+      break;
+    }
+
+    case Instruction::SUB_DOUBLE: {
+      Binop_23x<HSub>(instruction, Primitive::kPrimDouble);
+      break;
+    }
+
     case Instruction::ADD_INT_2ADDR: {
       Binop_12x<HAdd>(instruction, Primitive::kPrimInt);
       break;
     }
 
+    case Instruction::MUL_INT: {
+      Binop_23x<HMul>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::MUL_LONG: {
+      Binop_23x<HMul>(instruction, Primitive::kPrimLong);
+      break;
+    }
+
+    case Instruction::MUL_FLOAT: {
+      Binop_23x<HMul>(instruction, Primitive::kPrimFloat);
+      break;
+    }
+
+    case Instruction::MUL_DOUBLE: {
+      Binop_23x<HMul>(instruction, Primitive::kPrimDouble);
+      break;
+    }
+
     case Instruction::ADD_LONG_2ADDR: {
       Binop_12x<HAdd>(instruction, Primitive::kPrimLong);
       break;
@@ -738,6 +843,36 @@
       break;
     }
 
+    case Instruction::SUB_FLOAT_2ADDR: {
+      Binop_12x<HSub>(instruction, Primitive::kPrimFloat);
+      break;
+    }
+
+    case Instruction::SUB_DOUBLE_2ADDR: {
+      Binop_12x<HSub>(instruction, Primitive::kPrimDouble);
+      break;
+    }
+
+    case Instruction::MUL_INT_2ADDR: {
+      Binop_12x<HMul>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::MUL_LONG_2ADDR: {
+      Binop_12x<HMul>(instruction, Primitive::kPrimLong);
+      break;
+    }
+
+    case Instruction::MUL_FLOAT_2ADDR: {
+      Binop_12x<HMul>(instruction, Primitive::kPrimFloat);
+      break;
+    }
+
+    case Instruction::MUL_DOUBLE_2ADDR: {
+      Binop_12x<HMul>(instruction, Primitive::kPrimDouble);
+      break;
+    }
+
     case Instruction::ADD_INT_LIT16: {
       Binop_22s<HAdd>(instruction, false);
       break;
@@ -748,6 +883,11 @@
       break;
     }
 
+    case Instruction::MUL_INT_LIT16: {
+      Binop_22s<HMul>(instruction, false);
+      break;
+    }
+
     case Instruction::ADD_INT_LIT8: {
       Binop_22b<HAdd>(instruction, false);
       break;
@@ -758,6 +898,11 @@
       break;
     }
 
+    case Instruction::MUL_INT_LIT8: {
+      Binop_22b<HMul>(instruction, false);
+      break;
+    }
+
     case Instruction::NEW_INSTANCE: {
       current_block_->AddInstruction(
           new (arena_) HNewInstance(dex_offset, instruction.VRegB_21c()));
@@ -765,10 +910,88 @@
       break;
     }
 
+    case Instruction::NEW_ARRAY: {
+      HInstruction* length = LoadLocal(instruction.VRegB_22c(), Primitive::kPrimInt);
+      current_block_->AddInstruction(
+          new (arena_) HNewArray(length, dex_offset, instruction.VRegC_22c()));
+      UpdateLocal(instruction.VRegA_22c(), current_block_->GetLastInstruction());
+      break;
+    }
+
+    case Instruction::FILLED_NEW_ARRAY: {
+      uint32_t number_of_vreg_arguments = instruction.VRegA_35c();
+      uint32_t type_index = instruction.VRegB_35c();
+      uint32_t args[5];
+      instruction.GetVarArgs(args);
+      BuildFilledNewArray(dex_offset, type_index, number_of_vreg_arguments, false, args, 0);
+      break;
+    }
+
+    case Instruction::FILLED_NEW_ARRAY_RANGE: {
+      uint32_t number_of_vreg_arguments = instruction.VRegA_3rc();
+      uint32_t type_index = instruction.VRegB_3rc();
+      uint32_t register_index = instruction.VRegC_3rc();
+      BuildFilledNewArray(
+          dex_offset, type_index, number_of_vreg_arguments, true, nullptr, register_index);
+      break;
+    }
+
+    case Instruction::FILL_ARRAY_DATA: {
+      Temporaries temps(graph_, 1);
+      HInstruction* array = LoadLocal(instruction.VRegA_31t(), Primitive::kPrimNot);
+      HNullCheck* null_check = new (arena_) HNullCheck(array, dex_offset);
+      current_block_->AddInstruction(null_check);
+      temps.Add(null_check);
+
+      HInstruction* length = new (arena_) HArrayLength(null_check);
+      current_block_->AddInstruction(length);
+
+      int32_t payload_offset = instruction.VRegB_31t() + dex_offset;
+      const Instruction::ArrayDataPayload* payload =
+          reinterpret_cast<const Instruction::ArrayDataPayload*>(code_start_ + payload_offset);
+      const uint8_t* data = payload->data;
+      uint32_t element_count = payload->element_count;
+
+      // Implementation of this DEX instruction seems to be that the bounds check is
+      // done before doing any stores.
+      HInstruction* last_index = GetIntConstant(payload->element_count - 1);
+      current_block_->AddInstruction(new (arena_) HBoundsCheck(last_index, length, dex_offset));
+
+      switch (payload->element_width) {
+        case 1:
+          BuildFillArrayData(null_check, data, element_count, Primitive::kPrimByte, dex_offset);
+          break;
+        case 2:
+          BuildFillArrayData(null_check,
+                             reinterpret_cast<const uint16_t*>(data),
+                             element_count,
+                             Primitive::kPrimShort,
+                             dex_offset);
+          break;
+        case 4:
+          BuildFillArrayData(null_check,
+                             reinterpret_cast<const uint32_t*>(data),
+                             element_count,
+                             Primitive::kPrimInt,
+                             dex_offset);
+          break;
+        case 8:
+          BuildFillWideArrayData(null_check,
+                                 reinterpret_cast<const uint64_t*>(data),
+                                 element_count,
+                                 dex_offset);
+          break;
+        default:
+          LOG(FATAL) << "Unknown element width for " << payload->element_width;
+      }
+      break;
+    }
+
     case Instruction::MOVE_RESULT:
     case Instruction::MOVE_RESULT_WIDE:
     case Instruction::MOVE_RESULT_OBJECT:
-      UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+      UpdateLocal(instruction.VRegA(), latest_result_);
+      latest_result_ = nullptr;
       break;
 
     case Instruction::CMP_LONG: {
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index e68cdb0..c5e02db 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -48,7 +48,9 @@
         dex_file_(dex_file),
         dex_compilation_unit_(dex_compilation_unit),
         compiler_driver_(driver),
-        return_type_(Primitive::GetType(dex_compilation_unit_->GetShorty()[0])) {}
+        return_type_(Primitive::GetType(dex_compilation_unit_->GetShorty()[0])),
+        code_start_(nullptr),
+        latest_result_(nullptr) {}
 
   // Only for unit testing.
   HGraphBuilder(ArenaAllocator* arena, Primitive::Type return_type = Primitive::kPrimInt)
@@ -64,7 +66,9 @@
         dex_file_(nullptr),
         dex_compilation_unit_(nullptr),
         compiler_driver_(nullptr),
-        return_type_(return_type) {}
+        return_type_(return_type),
+        code_start_(nullptr),
+        latest_result_(nullptr) {}
 
   HGraph* BuildGraph(const DexFile::CodeItem& code);
 
@@ -95,6 +99,9 @@
   bool InitializeParameters(uint16_t number_of_parameters);
 
   template<typename T>
+  void Unop_12x(const Instruction& instruction, Primitive::Type type);
+
+  template<typename T>
   void Binop_23x(const Instruction& instruction, Primitive::Type type);
 
   template<typename T>
@@ -126,6 +133,31 @@
                    uint32_t* args,
                    uint32_t register_index);
 
+  // Builds a new array node and the instructions that fill it.
+  void BuildFilledNewArray(uint32_t dex_offset,
+                           uint32_t type_index,
+                           uint32_t number_of_vreg_arguments,
+                           bool is_range,
+                           uint32_t* args,
+                           uint32_t register_index);
+
+  // Fills the given object with data as specified in the fill-array-data
+  // instruction. Currently only used for non-reference and non-floating point
+  // arrays.
+  template <typename T>
+  void BuildFillArrayData(HInstruction* object,
+                          const T* data,
+                          uint32_t element_count,
+                          Primitive::Type anticipated_type,
+                          uint32_t dex_offset);
+
+  // Fills the given object with data as specified in the fill-array-data
+  // instruction. The data must be for long and double arrays.
+  void BuildFillWideArrayData(HInstruction* object,
+                              const uint64_t* data,
+                              uint32_t element_count,
+                              uint32_t dex_offset);
+
   ArenaAllocator* const arena_;
 
   // A list of the size of the dex code holding block information for
@@ -148,6 +180,14 @@
   CompilerDriver* const compiler_driver_;
   const Primitive::Type return_type_;
 
+  // The pointer in the dex file where the instructions of the code item
+  // being currently compiled start.
+  const uint16_t* code_start_;
+
+  // The last invoke or fill-new-array being built. Only to be
+  // used by move-result instructions.
+  HInstruction* latest_result_;
+
   DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
 };
 
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 29dbd8b..c4286a4 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -17,6 +17,7 @@
 #include "code_generator.h"
 
 #include "code_generator_arm.h"
+#include "code_generator_arm64.h"
 #include "code_generator_x86.h"
 #include "code_generator_x86_64.h"
 #include "compiled_method.h"
@@ -36,7 +37,7 @@
   const GrowableArray<HBasicBlock*>& blocks = GetGraph()->GetBlocks();
   DCHECK(blocks.Get(0) == GetGraph()->GetEntryBlock());
   DCHECK(GoesToNextBlock(GetGraph()->GetEntryBlock(), blocks.Get(1)));
-  block_labels_.SetSize(blocks.Size());
+  Initialize();
 
   DCHECK_EQ(frame_size_, kUninitializedFrameSize);
   if (!is_leaf) {
@@ -54,7 +55,7 @@
   HGraphVisitor* instruction_visitor = GetInstructionVisitor();
   for (size_t i = 0, e = blocks.Size(); i < e; ++i) {
     HBasicBlock* block = blocks.Get(i);
-    Bind(GetLabelOf(block));
+    Bind(block);
     for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
       HInstruction* current = it.Current();
       current->Accept(location_builder);
@@ -76,13 +77,13 @@
   const GrowableArray<HBasicBlock*>& blocks = GetGraph()->GetBlocks();
   DCHECK(blocks.Get(0) == GetGraph()->GetEntryBlock());
   DCHECK(GoesToNextBlock(GetGraph()->GetEntryBlock(), blocks.Get(1)));
-  block_labels_.SetSize(blocks.Size());
+  Initialize();
 
   GenerateFrameEntry();
   HGraphVisitor* instruction_visitor = GetInstructionVisitor();
   for (size_t i = 0, e = blocks.Size(); i < e; ++i) {
     HBasicBlock* block = blocks.Get(i);
-    Bind(GetLabelOf(block));
+    Bind(block);
     for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
       HInstruction* current = it.Current();
       current->Accept(instruction_visitor);
@@ -273,10 +274,6 @@
   return current->GetBlockId() + 1 == next->GetBlockId();
 }
 
-Label* CodeGenerator::GetLabelOf(HBasicBlock* block) const {
-  return block_labels_.GetRawStorage() + block->GetBlockId();
-}
-
 CodeGenerator* CodeGenerator::Create(ArenaAllocator* allocator,
                                      HGraph* graph,
                                      InstructionSet instruction_set) {
@@ -285,6 +282,9 @@
     case kThumb2: {
       return new (allocator) arm::CodeGeneratorARM(graph);
     }
+    case kArm64: {
+      return new (allocator) arm64::CodeGeneratorARM64(graph);
+    }
     case kMips:
       return nullptr;
     case kX86: {
@@ -477,8 +477,7 @@
       case Location::kRegister : {
         int id = location.reg();
         stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kInRegister, id);
-        if (current->GetType() == Primitive::kPrimDouble
-            || current->GetType() == Primitive::kPrimLong) {
+        if (current->GetType() == Primitive::kPrimLong) {
           stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kInRegister, id);
           ++i;
           DCHECK_LT(i, environment_size);
@@ -486,52 +485,55 @@
         break;
       }
 
+      case Location::kFpuRegister : {
+        int id = location.reg();
+        stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kInFpuRegister, id);
+        if (current->GetType() == Primitive::kPrimDouble) {
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kInFpuRegister, id);
+          ++i;
+          DCHECK_LT(i, environment_size);
+        }
+        break;
+      }
+
       default:
         LOG(FATAL) << "Unexpected kind " << location.GetKind();
     }
   }
 }
 
-size_t CodeGenerator::GetStackOffsetOfSavedRegister(size_t index) {
-  return first_register_slot_in_slow_path_ + index * GetWordSize();
-}
-
 void CodeGenerator::SaveLiveRegisters(LocationSummary* locations) {
   RegisterSet* register_set = locations->GetLiveRegisters();
-  uint32_t count = 0;
+  size_t stack_offset = first_register_slot_in_slow_path_;
   for (size_t i = 0, e = GetNumberOfCoreRegisters(); i < e; ++i) {
     if (register_set->ContainsCoreRegister(i)) {
-      size_t stack_offset = GetStackOffsetOfSavedRegister(count);
-      ++count;
-      SaveCoreRegister(Location::StackSlot(stack_offset), i);
       // If the register holds an object, update the stack mask.
       if (locations->RegisterContainsObject(i)) {
         locations->SetStackBit(stack_offset / kVRegSize);
       }
+      stack_offset += SaveCoreRegister(stack_offset, i);
     }
   }
 
   for (size_t i = 0, e = GetNumberOfFloatingPointRegisters(); i < e; ++i) {
     if (register_set->ContainsFloatingPointRegister(i)) {
-      LOG(FATAL) << "Unimplemented";
+      stack_offset += SaveFloatingPointRegister(stack_offset, i);
     }
   }
 }
 
 void CodeGenerator::RestoreLiveRegisters(LocationSummary* locations) {
   RegisterSet* register_set = locations->GetLiveRegisters();
-  uint32_t count = 0;
+  size_t stack_offset = first_register_slot_in_slow_path_;
   for (size_t i = 0, e = GetNumberOfCoreRegisters(); i < e; ++i) {
     if (register_set->ContainsCoreRegister(i)) {
-      size_t stack_offset = GetStackOffsetOfSavedRegister(count);
-      ++count;
-      RestoreCoreRegister(Location::StackSlot(stack_offset), i);
+      stack_offset += RestoreCoreRegister(stack_offset, i);
     }
   }
 
   for (size_t i = 0, e = GetNumberOfFloatingPointRegisters(); i < e; ++i) {
     if (register_set->ContainsFloatingPointRegister(i)) {
-      LOG(FATAL) << "Unimplemented";
+      stack_offset += RestoreFloatingPointRegister(stack_offset, i);
     }
   }
 }
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 4eba791..220d745 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -24,13 +24,13 @@
 #include "memory_region.h"
 #include "nodes.h"
 #include "stack_map_stream.h"
-#include "utils/assembler.h"
 
 namespace art {
 
 static size_t constexpr kVRegSize = 4;
 static size_t constexpr kUninitializedFrameSize = 0;
 
+class Assembler;
 class CodeGenerator;
 class DexCompilationUnit;
 class SrcMap;
@@ -53,18 +53,12 @@
 
 class SlowPathCode : public ArenaObject {
  public:
-  SlowPathCode() : entry_label_(), exit_label_() {}
+  SlowPathCode() {}
   virtual ~SlowPathCode() {}
 
-  Label* GetEntryLabel() { return &entry_label_; }
-  Label* GetExitLabel() { return &exit_label_; }
-
   virtual void EmitNativeCode(CodeGenerator* codegen) = 0;
 
  private:
-  Label entry_label_;
-  Label exit_label_;
-
   DISALLOW_COPY_AND_ASSIGN(SlowPathCode);
 };
 
@@ -80,7 +74,6 @@
 
   HGraph* GetGraph() const { return graph_; }
 
-  Label* GetLabelOf(HBasicBlock* block) const;
   bool GoesToNextBlock(HBasicBlock* current, HBasicBlock* next) const;
 
   size_t GetStackSlotOfParameter(HParameterValue* parameter) const {
@@ -90,9 +83,10 @@
         + parameter->GetIndex() * kVRegSize;
   }
 
+  virtual void Initialize() = 0;
   virtual void GenerateFrameEntry() = 0;
   virtual void GenerateFrameExit() = 0;
-  virtual void Bind(Label* label) = 0;
+  virtual void Bind(HBasicBlock* block) = 0;
   virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) = 0;
   virtual HGraphVisitor* GetLocationBuilder() = 0;
   virtual HGraphVisitor* GetInstructionVisitor() = 0;
@@ -116,8 +110,18 @@
   virtual void DumpCoreRegister(std::ostream& stream, int reg) const = 0;
   virtual void DumpFloatingPointRegister(std::ostream& stream, int reg) const = 0;
   virtual InstructionSet GetInstructionSet() const = 0;
-  virtual void SaveCoreRegister(Location stack_location, uint32_t reg_id) = 0;
-  virtual void RestoreCoreRegister(Location stack_location, uint32_t reg_id) = 0;
+  // Saves the register in the stack. Returns the size taken on stack.
+  virtual size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) = 0;
+  // Restores the register from the stack. Returns the size taken on stack.
+  virtual size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) = 0;
+  virtual size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
+    LOG(FATAL) << "Unimplemented";
+    return 0u;
+  }
+  virtual size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
+    LOG(FATAL) << "Unimplemented";
+    return 0u;
+  }
 
   void RecordPcInfo(HInstruction* instruction, uint32_t dex_pc);
 
@@ -151,6 +155,7 @@
   void ClearSpillSlotsFromLoopPhisInStackMap(HSuspendCheck* suspend_check) const;
 
   bool* GetBlockedCoreRegisters() const { return blocked_core_registers_; }
+  bool* GetBlockedFloatingPointRegisters() const { return blocked_fpu_registers_; }
 
  protected:
   CodeGenerator(HGraph* graph,
@@ -167,7 +172,6 @@
         number_of_fpu_registers_(number_of_fpu_registers),
         number_of_register_pairs_(number_of_register_pairs),
         graph_(graph),
-        block_labels_(graph->GetArena(), 0),
         pc_infos_(graph->GetArena(), 32),
         slow_paths_(graph->GetArena(), 8),
         is_leaf_(true),
@@ -205,8 +209,6 @@
 
   HGraph* const graph_;
 
-  // Labels for each block that will be compiled.
-  GrowableArray<Label> block_labels_;
   GrowableArray<PcInfo> pc_infos_;
   GrowableArray<SlowPathCode*> slow_paths_;
 
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 2be5c90..7b00d2f 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -60,7 +60,21 @@
 
 #define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())->
 
-class NullCheckSlowPathARM : public SlowPathCode {
+class SlowPathCodeARM : public SlowPathCode {
+ public:
+  SlowPathCodeARM() : entry_label_(), exit_label_() {}
+
+  Label* GetEntryLabel() { return &entry_label_; }
+  Label* GetExitLabel() { return &exit_label_; }
+
+ private:
+  Label entry_label_;
+  Label exit_label_;
+
+  DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARM);
+};
+
+class NullCheckSlowPathARM : public SlowPathCodeARM {
  public:
   explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {}
 
@@ -77,7 +91,7 @@
   DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
 };
 
-class StackOverflowCheckSlowPathARM : public SlowPathCode {
+class StackOverflowCheckSlowPathARM : public SlowPathCodeARM {
  public:
   StackOverflowCheckSlowPathARM() {}
 
@@ -91,12 +105,13 @@
   DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathARM);
 };
 
-class SuspendCheckSlowPathARM : public SlowPathCode {
+class SuspendCheckSlowPathARM : public SlowPathCodeARM {
  public:
   explicit SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor)
       : instruction_(instruction), successor_(successor) {}
 
   virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
     __ Bind(GetEntryLabel());
     codegen->SaveLiveRegisters(instruction_->GetLocations());
     int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pTestSuspend).Int32Value();
@@ -107,7 +122,7 @@
     if (successor_ == nullptr) {
       __ b(GetReturnLabel());
     } else {
-      __ b(codegen->GetLabelOf(successor_));
+      __ b(arm_codegen->GetLabelOf(successor_));
     }
   }
 
@@ -127,7 +142,7 @@
   DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
 };
 
-class BoundsCheckSlowPathARM : public SlowPathCode {
+class BoundsCheckSlowPathARM : public SlowPathCodeARM {
  public:
   BoundsCheckSlowPathARM(HBoundsCheck* instruction,
                          Location index_location,
@@ -137,7 +152,7 @@
         length_location_(length_location) {}
 
   virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
-    CodeGeneratorARM* arm_codegen = reinterpret_cast<CodeGeneratorARM*>(codegen);
+    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
     __ Bind(GetEntryLabel());
     InvokeRuntimeCallingConvention calling_convention;
     arm_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), index_location_);
@@ -195,16 +210,19 @@
   stream << ArmManagedRegister::FromDRegister(DRegister(reg));
 }
 
-void CodeGeneratorARM::SaveCoreRegister(Location stack_location, uint32_t reg_id) {
-  __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_location.GetStackIndex());
+size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
+  __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index);
+  return kArmWordSize;
 }
 
-void CodeGeneratorARM::RestoreCoreRegister(Location stack_location, uint32_t reg_id) {
-  __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_location.GetStackIndex());
+size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
+  __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index);
+  return kArmWordSize;
 }
 
 CodeGeneratorARM::CodeGeneratorARM(HGraph* graph)
     : CodeGenerator(graph, kNumberOfCoreRegisters, kNumberOfDRegisters, kNumberOfRegisterPairs),
+      block_labels_(graph->GetArena(), 0),
       location_builder_(graph, this),
       instruction_visitor_(graph, this),
       move_resolver_(graph->GetArena(), this),
@@ -220,19 +238,12 @@
       size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
       ArmManagedRegister pair =
           ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
+      DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
+      DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
+
       blocked_core_registers_[pair.AsRegisterPairLow()] = true;
       blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
-       // Block all other register pairs that share a register with `pair`.
-      for (int i = 0; i < kNumberOfRegisterPairs; i++) {
-        ArmManagedRegister current =
-            ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
-        if (current.AsRegisterPairLow() == pair.AsRegisterPairLow()
-            || current.AsRegisterPairLow() == pair.AsRegisterPairHigh()
-            || current.AsRegisterPairHigh() == pair.AsRegisterPairLow()
-            || current.AsRegisterPairHigh() == pair.AsRegisterPairHigh()) {
-          blocked_register_pairs_[i] = true;
-        }
-      }
+      UpdateBlockedPairRegisters();
       return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
     }
 
@@ -278,7 +289,6 @@
 
   // Reserve R4 for suspend check.
   blocked_core_registers_[R4] = true;
-  blocked_register_pairs_[R4_R5] = true;
 
   // Reserve thread register.
   blocked_core_registers_[TR] = true;
@@ -302,6 +312,19 @@
   blocked_fpu_registers_[D13] = true;
   blocked_fpu_registers_[D14] = true;
   blocked_fpu_registers_[D15] = true;
+
+  UpdateBlockedPairRegisters();
+}
+
+void CodeGeneratorARM::UpdateBlockedPairRegisters() const {
+  for (int i = 0; i < kNumberOfRegisterPairs; i++) {
+    ArmManagedRegister current =
+        ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
+    if (blocked_core_registers_[current.AsRegisterPairLow()]
+        || blocked_core_registers_[current.AsRegisterPairHigh()]) {
+      blocked_register_pairs_[i] = true;
+    }
+  }
 }
 
 InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen)
@@ -313,7 +336,7 @@
   bool skip_overflow_check = IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm);
   if (!skip_overflow_check) {
     if (kExplicitStackOverflowCheck) {
-      SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM();
+      SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM();
       AddSlowPath(slow_path);
 
       __ LoadFromOffset(kLoadWord, IP, TR, Thread::StackEndOffset<kArmWordSize>().Int32Value());
@@ -339,8 +362,8 @@
   __ PopList(1 << PC | 1 << R6 | 1 << R7);
 }
 
-void CodeGeneratorARM::Bind(Label* label) {
-  __ Bind(label);
+void CodeGeneratorARM::Bind(HBasicBlock* block) {
+  __ Bind(GetLabelOf(block));
 }
 
 Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const {
@@ -527,7 +550,7 @@
     return;
   }
 
-  if (instruction->AsIntConstant() != nullptr) {
+  if (instruction->IsIntConstant()) {
     int32_t value = instruction->AsIntConstant()->GetValue();
     if (location.IsRegister()) {
       __ LoadImmediate(location.As<Register>(), value);
@@ -536,7 +559,7 @@
       __ LoadImmediate(IP, value);
       __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
     }
-  } else if (instruction->AsLongConstant() != nullptr) {
+  } else if (instruction->IsLongConstant()) {
     int64_t value = instruction->AsLongConstant()->GetValue();
     if (location.IsRegisterPair()) {
       __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
@@ -548,7 +571,7 @@
       __ LoadImmediate(IP, High32Bits(value));
       __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
     }
-  } else if (instruction->AsLoadLocal() != nullptr) {
+  } else if (instruction->IsLoadLocal()) {
     uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
     switch (instruction->GetType()) {
       case Primitive::kPrimBoolean:
@@ -635,42 +658,57 @@
       new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
   HInstruction* cond = if_instr->InputAt(0);
   if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
-    locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
+    locations->SetInAt(0, Location::RequiresRegister());
   }
 }
 
 void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) {
   HInstruction* cond = if_instr->InputAt(0);
-  if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
-    // Condition has been materialized, compare the output to 0
-    DCHECK(if_instr->GetLocations()->InAt(0).IsRegister());
-    __ cmp(if_instr->GetLocations()->InAt(0).As<Register>(),
-           ShifterOperand(0));
-    __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), NE);
-  } else {
-    // Condition has not been materialized, use its inputs as the comparison and its
-    // condition as the branch condition.
-    LocationSummary* locations = cond->GetLocations();
-    if (locations->InAt(1).IsRegister()) {
-      __ cmp(locations->InAt(0).As<Register>(),
-             ShifterOperand(locations->InAt(1).As<Register>()));
-    } else {
-      DCHECK(locations->InAt(1).IsConstant());
-      int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
-      ShifterOperand operand;
-      if (ShifterOperand::CanHoldArm(value, &operand)) {
-        __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(value));
-      } else {
-        Register temp = IP;
-        __ LoadImmediate(temp, value);
-        __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(temp));
+  if (cond->IsIntConstant()) {
+    // Constant condition, statically compared against 1.
+    int32_t cond_value = cond->AsIntConstant()->GetValue();
+    if (cond_value == 1) {
+      if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
+                                     if_instr->IfTrueSuccessor())) {
+        __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
       }
+      return;
+    } else {
+      DCHECK_EQ(cond_value, 0);
     }
-    __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
-         ARMCondition(cond->AsCondition()->GetCondition()));
+  } else {
+    if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
+      // Condition has been materialized, compare the output to 0
+      DCHECK(if_instr->GetLocations()->InAt(0).IsRegister());
+      __ cmp(if_instr->GetLocations()->InAt(0).As<Register>(),
+             ShifterOperand(0));
+      __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), NE);
+    } else {
+      // Condition has not been materialized, use its inputs as the
+      // comparison and its condition as the branch condition.
+      LocationSummary* locations = cond->GetLocations();
+      if (locations->InAt(1).IsRegister()) {
+        __ cmp(locations->InAt(0).As<Register>(),
+               ShifterOperand(locations->InAt(1).As<Register>()));
+      } else {
+        DCHECK(locations->InAt(1).IsConstant());
+        int32_t value =
+            locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
+        ShifterOperand operand;
+        if (ShifterOperand::CanHoldArm(value, &operand)) {
+          __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(value));
+        } else {
+          Register temp = IP;
+          __ LoadImmediate(temp, value);
+          __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(temp));
+        }
+      }
+      __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()),
+           ARMCondition(cond->AsCondition()->GetCondition()));
+    }
   }
-
-  if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
+  if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
+                                 if_instr->IfFalseSuccessor())) {
     __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
   }
 }
@@ -679,10 +717,10 @@
 void LocationsBuilderARM::VisitCondition(HCondition* comp) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
-  locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)), Location::kDiesAtEntry);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)));
   if (comp->NeedsMaterialization()) {
-    locations->SetOut(Location::RequiresRegister());
+    locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   }
 }
 
@@ -810,6 +848,7 @@
 }
 
 void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
+  // Will be generated at use site.
 }
 
 void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
@@ -822,6 +861,26 @@
   // Will be generated at use site.
 }
 
+void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
+  locations->SetOut(Location::ConstantLocation(constant));
+}
+
+void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant) {
+  // Will be generated at use site.
+}
+
+void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
+  locations->SetOut(Location::ConstantLocation(constant));
+}
+
+void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant) {
+  // Will be generated at use site.
+}
+
 void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
   ret->SetLocations(nullptr);
 }
@@ -979,16 +1038,57 @@
   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
 }
 
+void LocationsBuilderARM::VisitNeg(HNeg* neg) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
+  switch (neg->GetResultType()) {
+    case Primitive::kPrimInt:
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetOut(Location::RequiresRegister());
+      break;
+
+    case Primitive::kPrimLong:
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
+  }
+}
+
+void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
+  LocationSummary* locations = neg->GetLocations();
+  Location out = locations->Out();
+  Location in = locations->InAt(0);
+  switch (neg->GetResultType()) {
+    case Primitive::kPrimInt:
+      DCHECK(in.IsRegister());
+      __ rsb(out.As<Register>(), in.As<Register>(), ShifterOperand(0));
+      break;
+
+    case Primitive::kPrimLong:
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
+  }
+}
+
 void LocationsBuilderARM::VisitAdd(HAdd* add) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
   switch (add->GetResultType()) {
     case Primitive::kPrimInt:
     case Primitive::kPrimLong: {
-      bool dies_at_entry = add->GetResultType() != Primitive::kPrimLong;
-      locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
-      locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)), dies_at_entry);
-      locations->SetOut(Location::RequiresRegister());
+      bool output_overlaps = (add->GetResultType() == Primitive::kPrimLong);
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
+      locations->SetOut(Location::RequiresRegister(), output_overlaps);
       break;
     }
 
@@ -1051,59 +1151,149 @@
   switch (sub->GetResultType()) {
     case Primitive::kPrimInt:
     case Primitive::kPrimLong: {
-      bool dies_at_entry = sub->GetResultType() != Primitive::kPrimLong;
-      locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
-      locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)), dies_at_entry);
-      locations->SetOut(Location::RequiresRegister());
+      bool output_overlaps = (sub->GetResultType() == Primitive::kPrimLong);
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)));
+      locations->SetOut(Location::RequiresRegister(), output_overlaps);
       break;
     }
-
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetOut(Location::RequiresFpuRegister());
       break;
-
+    }
     default:
-      LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
+      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
   }
 }
 
 void InstructionCodeGeneratorARM::VisitSub(HSub* sub) {
   LocationSummary* locations = sub->GetLocations();
+  Location out = locations->Out();
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
   switch (sub->GetResultType()) {
     case Primitive::kPrimInt: {
-      if (locations->InAt(1).IsRegister()) {
-        __ sub(locations->Out().As<Register>(),
-               locations->InAt(0).As<Register>(),
-               ShifterOperand(locations->InAt(1).As<Register>()));
+      if (second.IsRegister()) {
+        __ sub(out.As<Register>(), first.As<Register>(), ShifterOperand(second.As<Register>()));
       } else {
-        __ AddConstant(locations->Out().As<Register>(),
-                       locations->InAt(0).As<Register>(),
-                       -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue());
+        __ AddConstant(out.As<Register>(),
+                       first.As<Register>(),
+                       -second.GetConstant()->AsIntConstant()->GetValue());
       }
       break;
     }
 
-    case Primitive::kPrimLong:
-      __ subs(locations->Out().AsRegisterPairLow<Register>(),
-              locations->InAt(0).AsRegisterPairLow<Register>(),
-              ShifterOperand(locations->InAt(1).AsRegisterPairLow<Register>()));
-      __ sbc(locations->Out().AsRegisterPairHigh<Register>(),
-             locations->InAt(0).AsRegisterPairHigh<Register>(),
-             ShifterOperand(locations->InAt(1).AsRegisterPairHigh<Register>()));
+    case Primitive::kPrimLong: {
+      __ subs(out.AsRegisterPairLow<Register>(),
+              first.AsRegisterPairLow<Register>(),
+              ShifterOperand(second.AsRegisterPairLow<Register>()));
+      __ sbc(out.AsRegisterPairHigh<Register>(),
+             first.AsRegisterPairHigh<Register>(),
+             ShifterOperand(second.AsRegisterPairHigh<Register>()));
       break;
+    }
 
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
+    case Primitive::kPrimFloat: {
+      __ vsubs(FromDToLowS(out.As<DRegister>()),
+               FromDToLowS(first.As<DRegister>()),
+               FromDToLowS(second.As<DRegister>()));
       break;
+    }
+
+    case Primitive::kPrimDouble: {
+      __ vsubd(out.As<DRegister>(), first.As<DRegister>(), second.As<DRegister>());
+      break;
+    }
+
 
     default:
-      LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
+      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
+  }
+}
+
+void LocationsBuilderARM::VisitMul(HMul* mul) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
+  switch (mul->GetResultType()) {
+    case Primitive::kPrimInt:
+    case Primitive::kPrimLong:  {
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::RequiresRegister());
+      locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+      break;
+    }
+
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetOut(Location::RequiresFpuRegister());
+      break;
+    }
+
+    default:
+      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
+  }
+}
+
+void InstructionCodeGeneratorARM::VisitMul(HMul* mul) {
+  LocationSummary* locations = mul->GetLocations();
+  Location out = locations->Out();
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
+  switch (mul->GetResultType()) {
+    case Primitive::kPrimInt: {
+      __ mul(out.As<Register>(), first.As<Register>(), second.As<Register>());
+      break;
+    }
+    case Primitive::kPrimLong: {
+      Register out_hi = out.AsRegisterPairHigh<Register>();
+      Register out_lo = out.AsRegisterPairLow<Register>();
+      Register in1_hi = first.AsRegisterPairHigh<Register>();
+      Register in1_lo = first.AsRegisterPairLow<Register>();
+      Register in2_hi = second.AsRegisterPairHigh<Register>();
+      Register in2_lo = second.AsRegisterPairLow<Register>();
+
+      // Extra checks to protect caused by the existence of R1_R2.
+      // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
+      // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
+      DCHECK_NE(out_hi, in1_lo);
+      DCHECK_NE(out_hi, in2_lo);
+
+      // input: in1 - 64 bits, in2 - 64 bits
+      // output: out
+      // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
+      // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
+      // parts: out.lo = (in1.lo * in2.lo)[31:0]
+
+      // IP <- in1.lo * in2.hi
+      __ mul(IP, in1_lo, in2_hi);
+      // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo
+      __ mla(out_hi, in1_hi, in2_lo, IP);
+      // out.lo <- (in1.lo * in2.lo)[31:0];
+      __ umull(out_lo, IP, in1_lo, in2_lo);
+      // out.hi <- in2.hi * in1.lo +  in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
+      __ add(out_hi, out_hi, ShifterOperand(IP));
+      break;
+    }
+
+    case Primitive::kPrimFloat: {
+      __ vmuls(FromDToLowS(out.As<DRegister>()),
+               FromDToLowS(first.As<DRegister>()),
+               FromDToLowS(second.As<DRegister>()));
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      __ vmuld(out.As<DRegister>(), first.As<DRegister>(), second.As<DRegister>());
+      break;
+    }
+
+    default:
+      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
   }
 }
 
@@ -1129,6 +1319,29 @@
   DCHECK(!codegen_->IsLeafMethod());
 }
 
+void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+  InvokeRuntimeCallingConvention calling_convention;
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+  locations->SetOut(Location::RegisterLocation(R0));
+  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
+}
+
+void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
+  InvokeRuntimeCallingConvention calling_convention;
+  LoadCurrentMethod(calling_convention.GetRegisterAt(1));
+  __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
+
+  int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocArrayWithAccessCheck).Int32Value();
+  __ LoadFromOffset(kLoadWord, LR, TR, offset);
+  __ blx(LR);
+
+  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+  DCHECK(!codegen_->IsLeafMethod());
+}
+
 void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
@@ -1145,25 +1358,41 @@
   // Nothing to do, the parameter is already at its location.
 }
 
-void LocationsBuilderARM::VisitNot(HNot* instruction) {
+void LocationsBuilderARM::VisitNot(HNot* not_) {
   LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
-  locations->SetOut(Location::RequiresRegister());
+      new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
-void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
-  LocationSummary* locations = instruction->GetLocations();
-  __ eor(locations->Out().As<Register>(),
-         locations->InAt(0).As<Register>(), ShifterOperand(1));
+void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
+  LocationSummary* locations = not_->GetLocations();
+  Location out = locations->Out();
+  Location in = locations->InAt(0);
+  switch (not_->InputAt(0)->GetType()) {
+    case Primitive::kPrimBoolean:
+      __ eor(out.As<Register>(), in.As<Register>(), ShifterOperand(1));
+      break;
+
+    case Primitive::kPrimInt:
+      __ mvn(out.As<Register>(), ShifterOperand(in.As<Register>()));
+      break;
+
+    case Primitive::kPrimLong:
+      LOG(FATAL) << "Not yet implemented type for not operation " << not_->GetResultType();
+      break;
+
+    default:
+      LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
+  }
 }
 
 void LocationsBuilderARM::VisitCompare(HCompare* compare) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
-  locations->SetInAt(1, Location::RequiresRegister(), Location::kDiesAtEntry);
-  locations->SetOut(Location::RequiresRegister());
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
 void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) {
@@ -1219,9 +1448,8 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot;
-  bool dies_at_entry = !is_object_type;
-  locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
-  locations->SetInAt(1, Location::RequiresRegister(), dies_at_entry);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
   // Temporary registers for the write barrier.
   if (is_object_type) {
     locations->AddTemp(Location::RequiresRegister());
@@ -1281,8 +1509,8 @@
 void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
-  locations->SetOut(Location::RequiresRegister());
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
 void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
@@ -1349,7 +1577,7 @@
 }
 
 void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
-  SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
+  SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction);
   codegen_->AddSlowPath(slow_path);
 
   LocationSummary* locations = instruction->GetLocations();
@@ -1368,10 +1596,9 @@
 void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
-  locations->SetInAt(
-      1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
-  locations->SetOut(Location::RequiresRegister());
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
 void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) {
@@ -1481,10 +1708,9 @@
     locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
     locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
   } else {
-    locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
-    locations->SetInAt(
-        1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
-    locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry);
+    locations->SetInAt(0, Location::RequiresRegister());
+    locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+    locations->SetInAt(2, Location::RequiresRegister());
   }
 }
 
@@ -1571,8 +1797,8 @@
 void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
-  locations->SetOut(Location::RequiresRegister());
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
 void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) {
@@ -1595,7 +1821,7 @@
 
 void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) {
   LocationSummary* locations = instruction->GetLocations();
-  SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
+  SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM(
       instruction, locations->InAt(0), locations->InAt(1));
   codegen_->AddSlowPath(slow_path);
 
@@ -1693,7 +1919,7 @@
     }
   } else {
     DCHECK(source.IsConstant());
-    DCHECK(source.GetConstant()->AsIntConstant() != nullptr);
+    DCHECK(source.GetConstant()->IsIntConstant());
     int32_t value = source.GetConstant()->AsIntConstant()->GetValue();
     if (destination.IsRegister()) {
       __ LoadImmediate(destination.As<Register>(), value);
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 874db0f..1fe8a7e 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -140,10 +140,10 @@
 
   virtual void GenerateFrameEntry() OVERRIDE;
   virtual void GenerateFrameExit() OVERRIDE;
-  virtual void Bind(Label* label) OVERRIDE;
+  virtual void Bind(HBasicBlock* block) OVERRIDE;
   virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
-  virtual void SaveCoreRegister(Location stack_location, uint32_t reg_id) OVERRIDE;
-  virtual void RestoreCoreRegister(Location stack_location, uint32_t reg_id) OVERRIDE;
+  virtual size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  virtual size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
 
   virtual size_t GetWordSize() const OVERRIDE {
     return kArmWordSize;
@@ -164,6 +164,7 @@
   }
 
   virtual void SetupBlockedRegisters() const OVERRIDE;
+
   virtual Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
 
   virtual Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
@@ -171,6 +172,9 @@
   virtual void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
   virtual void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
 
+  // Blocks all register pairs made out of blocked core registers.
+  void UpdateBlockedPairRegisters() const;
+
   ParallelMoveResolverARM* GetMoveResolver() {
     return &move_resolver_;
   }
@@ -187,7 +191,17 @@
   // Emit a write barrier.
   void MarkGCCard(Register temp, Register card, Register object, Register value);
 
+  Label* GetLabelOf(HBasicBlock* block) const {
+    return block_labels_.GetRawStorage() + block->GetBlockId();
+  }
+
+  virtual void Initialize() OVERRIDE {
+    block_labels_.SetSize(GetGraph()->GetBlocks().Size());
+  }
+
  private:
+  // Labels for each block that will be compiled.
+  GrowableArray<Label> block_labels_;
   LocationsBuilderARM location_builder_;
   InstructionCodeGeneratorARM instruction_visitor_;
   ParallelMoveResolverARM move_resolver_;
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
new file mode 100644
index 0000000..79528ac
--- /dev/null
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -0,0 +1,1205 @@
+/*
+ * Copyright (C) 2014 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 "code_generator_arm64.h"
+
+#include "entrypoints/quick/quick_entrypoints.h"
+#include "gc/accounting/card_table.h"
+#include "mirror/array-inl.h"
+#include "mirror/art_method.h"
+#include "mirror/class.h"
+#include "thread.h"
+#include "utils/arm64/assembler_arm64.h"
+#include "utils/assembler.h"
+#include "utils/stack_checks.h"
+
+
+using namespace vixl;   // NOLINT(build/namespaces)
+
+#ifdef __
+#error "ARM64 Codegen VIXL macro-assembler macro already defined."
+#endif
+
+
+namespace art {
+
+namespace arm64 {
+
+static bool IsFPType(Primitive::Type type) {
+  return type == Primitive::kPrimFloat || type == Primitive::kPrimDouble;
+}
+
+// TODO: clean-up some of the constant definitions.
+static constexpr size_t kHeapRefSize = sizeof(mirror::HeapReference<mirror::Object>);
+static constexpr int kCurrentMethodStackOffset = 0;
+
+namespace {
+// Convenience helpers to ease conversion to and from VIXL operands.
+
+int VIXLRegCodeFromART(int code) {
+  // TODO: static check?
+  DCHECK_EQ(SP, 31);
+  DCHECK_EQ(WSP, 31);
+  DCHECK_EQ(XZR, 32);
+  DCHECK_EQ(WZR, 32);
+  if (code == SP) {
+    return vixl::kSPRegInternalCode;
+  }
+  if (code == XZR) {
+    return vixl::kZeroRegCode;
+  }
+  return code;
+}
+
+int ARTRegCodeFromVIXL(int code) {
+  // TODO: static check?
+  DCHECK_EQ(SP, 31);
+  DCHECK_EQ(WSP, 31);
+  DCHECK_EQ(XZR, 32);
+  DCHECK_EQ(WZR, 32);
+  if (code == vixl::kSPRegInternalCode) {
+    return SP;
+  }
+  if (code == vixl::kZeroRegCode) {
+    return XZR;
+  }
+  return code;
+}
+
+Register XRegisterFrom(Location location) {
+  return Register::XRegFromCode(VIXLRegCodeFromART(location.reg()));
+}
+
+Register WRegisterFrom(Location location) {
+  return Register::WRegFromCode(VIXLRegCodeFromART(location.reg()));
+}
+
+Register RegisterFrom(Location location, Primitive::Type type) {
+  DCHECK(type != Primitive::kPrimVoid && !IsFPType(type));
+  return type == Primitive::kPrimLong ? XRegisterFrom(location) : WRegisterFrom(location);
+}
+
+Register OutputRegister(HInstruction* instr) {
+  return RegisterFrom(instr->GetLocations()->Out(), instr->GetType());
+}
+
+Register InputRegisterAt(HInstruction* instr, int input_index) {
+  return RegisterFrom(instr->GetLocations()->InAt(input_index),
+                      instr->InputAt(input_index)->GetType());
+}
+
+int64_t Int64ConstantFrom(Location location) {
+  HConstant* instr = location.GetConstant();
+  return instr->IsIntConstant() ? instr->AsIntConstant()->GetValue()
+                                : instr->AsLongConstant()->GetValue();
+}
+
+Operand OperandFrom(Location location, Primitive::Type type) {
+  if (location.IsRegister()) {
+    return Operand(RegisterFrom(location, type));
+  } else {
+    return Operand(Int64ConstantFrom(location));
+  }
+}
+
+Operand InputOperandAt(HInstruction* instr, int input_index) {
+  return OperandFrom(instr->GetLocations()->InAt(input_index),
+                     instr->InputAt(input_index)->GetType());
+}
+
+MemOperand StackOperandFrom(Location location) {
+  return MemOperand(sp, location.GetStackIndex());
+}
+
+MemOperand HeapOperand(const Register& base, Offset offset) {
+  // A heap reference must be 32bit, so fit in a W register.
+  DCHECK(base.IsW());
+  return MemOperand(base.X(), offset.SizeValue());
+}
+
+MemOperand HeapOperandFrom(Location location, Primitive::Type type, Offset offset) {
+  return HeapOperand(RegisterFrom(location, type), offset);
+}
+
+Location LocationFrom(const Register& reg) {
+  return Location::RegisterLocation(ARTRegCodeFromVIXL(reg.code()));
+}
+
+}  // namespace
+
+inline Condition ARM64Condition(IfCondition cond) {
+  switch (cond) {
+    case kCondEQ: return eq;
+    case kCondNE: return ne;
+    case kCondLT: return lt;
+    case kCondLE: return le;
+    case kCondGT: return gt;
+    case kCondGE: return ge;
+    default:
+      LOG(FATAL) << "Unknown if condition";
+  }
+  return nv;  // Unreachable.
+}
+
+static const Register kRuntimeParameterCoreRegisters[] = { x0, x1, x2, x3, x4, x5, x6, x7 };
+static constexpr size_t kRuntimeParameterCoreRegistersLength =
+    arraysize(kRuntimeParameterCoreRegisters);
+static const FPRegister kRuntimeParameterFpuRegisters[] = { };
+static constexpr size_t kRuntimeParameterFpuRegistersLength = 0;
+
+class InvokeRuntimeCallingConvention : public CallingConvention<Register, FPRegister> {
+ public:
+  static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
+
+  InvokeRuntimeCallingConvention()
+      : CallingConvention(kRuntimeParameterCoreRegisters,
+                          kRuntimeParameterCoreRegistersLength,
+                          kRuntimeParameterFpuRegisters,
+                          kRuntimeParameterFpuRegistersLength) {}
+
+  Location GetReturnLocation(Primitive::Type return_type);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
+};
+
+Location InvokeRuntimeCallingConvention::GetReturnLocation(Primitive::Type return_type) {
+  DCHECK_NE(return_type, Primitive::kPrimVoid);
+  if (return_type == Primitive::kPrimFloat || return_type == Primitive::kPrimDouble) {
+    LOG(FATAL) << "Unimplemented return type " << return_type;
+  }
+  return LocationFrom(x0);
+}
+
+#define __ reinterpret_cast<Arm64Assembler*>(codegen->GetAssembler())->vixl_masm_->
+
+class SlowPathCodeARM64 : public SlowPathCode {
+ public:
+  SlowPathCodeARM64() : entry_label_(), exit_label_() {}
+
+  vixl::Label* GetEntryLabel() { return &entry_label_; }
+  vixl::Label* GetExitLabel() { return &exit_label_; }
+
+ private:
+  vixl::Label entry_label_;
+  vixl::Label exit_label_;
+
+  DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARM64);
+};
+
+class BoundsCheckSlowPathARM64 : public SlowPathCodeARM64 {
+ public:
+  explicit BoundsCheckSlowPathARM64(HBoundsCheck* instruction,
+                                    Location index_location,
+                                    Location length_location)
+      : instruction_(instruction),
+        index_location_(index_location),
+        length_location_(length_location) {}
+
+  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    CodeGeneratorARM64* arm64_codegen = reinterpret_cast<CodeGeneratorARM64*>(codegen);
+    __ Bind(GetEntryLabel());
+    InvokeRuntimeCallingConvention calling_convention;
+    arm64_codegen->MoveHelper(LocationFrom(calling_convention.GetRegisterAt(0)),
+                              index_location_, Primitive::kPrimInt);
+    arm64_codegen->MoveHelper(LocationFrom(calling_convention.GetRegisterAt(1)),
+                              length_location_, Primitive::kPrimInt);
+    size_t offset = QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pThrowArrayBounds).SizeValue();
+    __ Ldr(lr, MemOperand(tr, offset));
+    __ Blr(lr);
+    codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
+  }
+
+ private:
+  HBoundsCheck* const instruction_;
+  const Location index_location_;
+  const Location length_location_;
+
+  DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM64);
+};
+
+class NullCheckSlowPathARM64 : public SlowPathCodeARM64 {
+ public:
+  explicit NullCheckSlowPathARM64(HNullCheck* instr) : instruction_(instr) {}
+
+  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    __ Bind(GetEntryLabel());
+    int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pThrowNullPointer).Int32Value();
+    __ Ldr(lr, MemOperand(tr, offset));
+    __ Blr(lr);
+    codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
+  }
+
+ private:
+  HNullCheck* const instruction_;
+
+  DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM64);
+};
+
+class SuspendCheckSlowPathARM64 : public SlowPathCodeARM64 {
+ public:
+  explicit SuspendCheckSlowPathARM64(HSuspendCheck* instruction,
+                                     HBasicBlock* successor)
+      : instruction_(instruction), successor_(successor) {}
+
+  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    size_t offset = QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pTestSuspend).SizeValue();
+    __ Bind(GetEntryLabel());
+    __ Ldr(lr, MemOperand(tr, offset));
+    __ Blr(lr);
+    codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
+    __ B(GetReturnLabel());
+  }
+
+  vixl::Label* GetReturnLabel() {
+    DCHECK(successor_ == nullptr);
+    return &return_label_;
+  }
+
+
+ private:
+  HSuspendCheck* const instruction_;
+  // If not null, the block to branch to after the suspend check.
+  HBasicBlock* const successor_;
+
+  // If `successor_` is null, the label to branch to after the suspend check.
+  vixl::Label return_label_;
+
+  DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM64);
+};
+
+#undef __
+
+Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
+  Location next_location;
+  if (type == Primitive::kPrimVoid) {
+    LOG(FATAL) << "Unreachable type " << type;
+  }
+
+  if (type == Primitive::kPrimFloat || type == Primitive::kPrimDouble) {
+    LOG(FATAL) << "Unimplemented type " << type;
+  }
+
+  if (gp_index_ < calling_convention.GetNumberOfRegisters()) {
+    next_location = LocationFrom(calling_convention.GetRegisterAt(gp_index_));
+    if (type == Primitive::kPrimLong) {
+      // Double stack slot reserved on the stack.
+      stack_index_++;
+    }
+  } else {  // Stack.
+    if (type == Primitive::kPrimLong) {
+      next_location = Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_));
+      // Double stack slot reserved on the stack.
+      stack_index_++;
+    } else {
+      next_location = Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_));
+    }
+  }
+  // Move to the next register/stack slot.
+  gp_index_++;
+  stack_index_++;
+  return next_location;
+}
+
+CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph)
+    : CodeGenerator(graph,
+                    kNumberOfAllocatableRegisters,
+                    kNumberOfAllocatableFloatingPointRegisters,
+                    kNumberOfAllocatableRegisterPairs),
+      block_labels_(nullptr),
+      location_builder_(graph, this),
+      instruction_visitor_(graph, this) {}
+
+#define __ reinterpret_cast<Arm64Assembler*>(GetAssembler())->vixl_masm_->
+
+void CodeGeneratorARM64::GenerateFrameEntry() {
+  // TODO: Add proper support for the stack overflow check.
+  UseScratchRegisterScope temps(assembler_.vixl_masm_);
+  Register temp = temps.AcquireX();
+  __ Add(temp, sp, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm64)));
+  __ Ldr(temp, MemOperand(temp, 0));
+  RecordPcInfo(nullptr, 0);
+
+  CPURegList preserved_regs = GetFramePreservedRegisters();
+  int frame_size = GetFrameSize();
+  core_spill_mask_ |= preserved_regs.list();
+
+  __ Str(w0, MemOperand(sp, -frame_size, PreIndex));
+  __ PokeCPURegList(preserved_regs, frame_size - preserved_regs.TotalSizeInBytes());
+
+  // Stack layout:
+  // sp[frame_size - 8]        : lr.
+  // ...                       : other preserved registers.
+  // sp[frame_size - regs_size]: first preserved register.
+  // ...                       : reserved frame space.
+  // sp[0]                     : context pointer.
+}
+
+void CodeGeneratorARM64::GenerateFrameExit() {
+  int frame_size = GetFrameSize();
+  CPURegList preserved_regs = GetFramePreservedRegisters();
+  __ PeekCPURegList(preserved_regs, frame_size - preserved_regs.TotalSizeInBytes());
+  __ Drop(frame_size);
+}
+
+void CodeGeneratorARM64::Bind(HBasicBlock* block) {
+  __ Bind(GetLabelOf(block));
+}
+
+void CodeGeneratorARM64::MoveHelper(Location destination,
+                                    Location source,
+                                    Primitive::Type type) {
+  if (source.Equals(destination)) {
+    return;
+  }
+  if (destination.IsRegister()) {
+    Register dst = RegisterFrom(destination, type);
+    if (source.IsRegister()) {
+      Register src = RegisterFrom(source, type);
+      DCHECK(dst.IsSameSizeAndType(src));
+      __ Mov(dst, src);
+    } else {
+      DCHECK(dst.Is64Bits() || !source.IsDoubleStackSlot());
+      __ Ldr(dst, StackOperandFrom(source));
+    }
+  } else {
+    DCHECK(destination.IsStackSlot() || destination.IsDoubleStackSlot());
+    if (source.IsRegister()) {
+      __ Str(RegisterFrom(source, type), StackOperandFrom(destination));
+    } else {
+      UseScratchRegisterScope temps(assembler_.vixl_masm_);
+      Register temp = destination.IsDoubleStackSlot() ? temps.AcquireX() : temps.AcquireW();
+      __ Ldr(temp, StackOperandFrom(source));
+      __ Str(temp, StackOperandFrom(destination));
+    }
+  }
+}
+
+void CodeGeneratorARM64::Move(HInstruction* instruction,
+                              Location location,
+                              HInstruction* move_for) {
+  LocationSummary* locations = instruction->GetLocations();
+  if (locations != nullptr && locations->Out().Equals(location)) {
+    return;
+  }
+
+  Primitive::Type type = instruction->GetType();
+
+  if (instruction->IsIntConstant() || instruction->IsLongConstant()) {
+    int64_t value = instruction->IsIntConstant() ? instruction->AsIntConstant()->GetValue()
+                                                 : instruction->AsLongConstant()->GetValue();
+    if (location.IsRegister()) {
+      Register dst = RegisterFrom(location, type);
+      DCHECK((instruction->IsIntConstant() && dst.Is32Bits()) ||
+             (instruction->IsLongConstant() && dst.Is64Bits()));
+      __ Mov(dst, value);
+    } else {
+      DCHECK(location.IsStackSlot() || location.IsDoubleStackSlot());
+      UseScratchRegisterScope temps(assembler_.vixl_masm_);
+      Register temp = instruction->IsIntConstant() ? temps.AcquireW() : temps.AcquireX();
+      __ Mov(temp, value);
+      __ Str(temp, StackOperandFrom(location));
+    }
+
+  } else if (instruction->IsLoadLocal()) {
+    uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
+    switch (type) {
+      case Primitive::kPrimNot:
+      case Primitive::kPrimBoolean:
+      case Primitive::kPrimByte:
+      case Primitive::kPrimChar:
+      case Primitive::kPrimShort:
+      case Primitive::kPrimInt:
+        MoveHelper(location, Location::StackSlot(stack_slot), type);
+        break;
+      case Primitive::kPrimLong:
+        MoveHelper(location, Location::DoubleStackSlot(stack_slot), type);
+        break;
+      default:
+        LOG(FATAL) << "Unimplemented type" << type;
+    }
+
+  } else {
+    DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
+    MoveHelper(location, locations->Out(), type);
+  }
+}
+
+size_t CodeGeneratorARM64::FrameEntrySpillSize() const {
+  return GetFramePreservedRegistersSize();
+}
+
+Location CodeGeneratorARM64::GetStackLocation(HLoadLocal* load) const {
+  Primitive::Type type = load->GetType();
+  switch (type) {
+    case Primitive::kPrimNot:
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+      return Location::StackSlot(GetStackSlot(load->GetLocal()));
+    case Primitive::kPrimLong:
+      return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      LOG(FATAL) << "Unimplemented type " << type;
+      break;
+    case Primitive::kPrimVoid:
+    default:
+      LOG(FATAL) << "Unexpected type " << type;
+  }
+  LOG(FATAL) << "Unreachable";
+  return Location::NoLocation();
+}
+
+void CodeGeneratorARM64::MarkGCCard(Register object, Register value) {
+  UseScratchRegisterScope temps(assembler_.vixl_masm_);
+  Register card = temps.AcquireX();
+  Register temp = temps.AcquireX();
+  vixl::Label done;
+  __ Cbz(value, &done);
+  __ Ldr(card, MemOperand(tr, Thread::CardTableOffset<kArm64WordSize>().Int32Value()));
+  __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
+  __ Strb(card, MemOperand(card, temp));
+  __ Bind(&done);
+}
+
+void CodeGeneratorARM64::SetupBlockedRegisters() const {
+  // Block reserved registers:
+  //   ip0 (VIXL temporary)
+  //   ip1 (VIXL temporary)
+  //   xSuspend (Suspend counter)
+  //   lr
+  // sp is not part of the allocatable registers, so we don't need to block it.
+  CPURegList reserved_core_registers = vixl_reserved_core_registers;
+  reserved_core_registers.Combine(runtime_reserved_core_registers);
+  // TODO: See if we should instead allow allocating but preserve those if used.
+  reserved_core_registers.Combine(quick_callee_saved_registers);
+  while (!reserved_core_registers.IsEmpty()) {
+    blocked_core_registers_[reserved_core_registers.PopLowestIndex().code()] = true;
+  }
+}
+
+Location CodeGeneratorARM64::AllocateFreeRegister(Primitive::Type type) const {
+  if (type == Primitive::kPrimVoid) {
+    LOG(FATAL) << "Unreachable type " << type;
+  }
+
+  if (type == Primitive::kPrimFloat || type == Primitive::kPrimDouble) {
+    LOG(FATAL) << "Unimplemented support for floating-point";
+  }
+
+  ssize_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfXRegisters);
+  DCHECK_NE(reg, -1);
+  blocked_core_registers_[reg] = true;
+
+  if (IsFPType(type)) {
+    return Location::FpuRegisterLocation(reg);
+  } else {
+    return Location::RegisterLocation(reg);
+  }
+}
+
+void CodeGeneratorARM64::DumpCoreRegister(std::ostream& stream, int reg) const {
+  stream << Arm64ManagedRegister::FromXRegister(XRegister(reg));
+}
+
+void CodeGeneratorARM64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
+  stream << Arm64ManagedRegister::FromDRegister(DRegister(reg));
+}
+
+#undef __
+#define __ assembler_->vixl_masm_->
+
+InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph,
+                                                             CodeGeneratorARM64* codegen)
+      : HGraphVisitor(graph),
+        assembler_(codegen->GetAssembler()),
+        codegen_(codegen) {}
+
+#define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M)              \
+  M(ArrayGet)                                              \
+  M(ArraySet)                                              \
+  M(DoubleConstant)                                        \
+  M(FloatConstant)                                         \
+  M(Mul)                                                   \
+  M(Neg)                                                   \
+  M(NewArray)                                              \
+  M(ParallelMove)
+
+#define UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name) name##UnimplementedInstructionBreakCode
+
+enum UnimplementedInstructionBreakCode {
+#define ENUM_UNIMPLEMENTED_INSTRUCTION(name) UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name),
+  FOR_EACH_UNIMPLEMENTED_INSTRUCTION(ENUM_UNIMPLEMENTED_INSTRUCTION)
+#undef ENUM_UNIMPLEMENTED_INSTRUCTION
+};
+
+#define DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS(name)                               \
+  void InstructionCodeGeneratorARM64::Visit##name(H##name* instr) {                   \
+    __ Brk(UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name));                               \
+  }                                                                                   \
+  void LocationsBuilderARM64::Visit##name(H##name* instr) {                           \
+    LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr); \
+    locations->SetOut(Location::Any());                                               \
+  }
+  FOR_EACH_UNIMPLEMENTED_INSTRUCTION(DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS)
+#undef DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS
+
+#undef UNIMPLEMENTED_INSTRUCTION_BREAK_CODE
+
+void LocationsBuilderARM64::HandleAddSub(HBinaryOperation* instr) {
+  DCHECK(instr->IsAdd() || instr->IsSub());
+  DCHECK_EQ(instr->InputCount(), 2U);
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
+  Primitive::Type type = instr->GetResultType();
+  switch (type) {
+    case Primitive::kPrimInt:
+    case Primitive::kPrimLong: {
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
+      locations->SetOut(Location::RequiresRegister());
+      break;
+    }
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      LOG(FATAL) << "Unexpected " << instr->DebugName() <<  " type " << type;
+      break;
+    default:
+      LOG(FATAL) << "Unimplemented " << instr->DebugName() << " type " << type;
+  }
+}
+
+void InstructionCodeGeneratorARM64::HandleAddSub(HBinaryOperation* instr) {
+  DCHECK(instr->IsAdd() || instr->IsSub());
+
+  Primitive::Type type = instr->GetType();
+  Register dst = OutputRegister(instr);
+  Register lhs = InputRegisterAt(instr, 0);
+  Operand rhs = InputOperandAt(instr, 1);
+
+  switch (type) {
+    case Primitive::kPrimInt:
+    case Primitive::kPrimLong:
+      if (instr->IsAdd()) {
+        __ Add(dst, lhs, rhs);
+      } else {
+        __ Sub(dst, lhs, rhs);
+      }
+      break;
+
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      LOG(FATAL) << "Unexpected add/sub type " << type;
+      break;
+    default:
+      LOG(FATAL) << "Unimplemented add/sub type " << type;
+  }
+}
+
+void LocationsBuilderARM64::VisitAdd(HAdd* instruction) {
+  HandleAddSub(instruction);
+}
+
+void InstructionCodeGeneratorARM64::VisitAdd(HAdd* instruction) {
+  HandleAddSub(instruction);
+}
+
+void LocationsBuilderARM64::VisitArrayLength(HArrayLength* instruction) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM64::VisitArrayLength(HArrayLength* instruction) {
+  __ Ldr(OutputRegister(instruction),
+         HeapOperand(InputRegisterAt(instruction, 0), mirror::Array::LengthOffset()));
+}
+
+void LocationsBuilderARM64::VisitCompare(HCompare* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM64::VisitCompare(HCompare* instruction) {
+  Primitive::Type in_type = instruction->InputAt(0)->GetType();
+
+  DCHECK_EQ(in_type, Primitive::kPrimLong);
+  switch (in_type) {
+    case Primitive::kPrimLong: {
+      vixl::Label done;
+      Register result = OutputRegister(instruction);
+      Register left = InputRegisterAt(instruction, 0);
+      Operand right = InputOperandAt(instruction, 1);
+      __ Subs(result, left, right);
+      __ B(eq, &done);
+      __ Mov(result, 1);
+      __ Cneg(result, result, le);
+      __ Bind(&done);
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unimplemented compare type " << in_type;
+  }
+}
+
+void LocationsBuilderARM64::VisitCondition(HCondition* instruction) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+  if (instruction->NeedsMaterialization()) {
+    locations->SetOut(Location::RequiresRegister());
+  }
+}
+
+void InstructionCodeGeneratorARM64::VisitCondition(HCondition* instruction) {
+  if (!instruction->NeedsMaterialization()) {
+    return;
+  }
+
+  LocationSummary* locations = instruction->GetLocations();
+  Register lhs = InputRegisterAt(instruction, 0);
+  Operand rhs = InputOperandAt(instruction, 1);
+  Register res = RegisterFrom(locations->Out(), instruction->GetType());
+  Condition cond = ARM64Condition(instruction->GetCondition());
+
+  __ Cmp(lhs, rhs);
+  __ Csel(res, vixl::Assembler::AppropriateZeroRegFor(res), Operand(1), InvertCondition(cond));
+}
+
+#define FOR_EACH_CONDITION_INSTRUCTION(M)                                                \
+  M(Equal)                                                                               \
+  M(NotEqual)                                                                            \
+  M(LessThan)                                                                            \
+  M(LessThanOrEqual)                                                                     \
+  M(GreaterThan)                                                                         \
+  M(GreaterThanOrEqual)
+#define DEFINE_CONDITION_VISITORS(Name)                                                  \
+void LocationsBuilderARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); }         \
+void InstructionCodeGeneratorARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); }
+FOR_EACH_CONDITION_INSTRUCTION(DEFINE_CONDITION_VISITORS)
+#undef FOR_EACH_CONDITION_INSTRUCTION
+
+void LocationsBuilderARM64::VisitExit(HExit* exit) {
+  exit->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorARM64::VisitExit(HExit* exit) {
+  if (kIsDebugBuild) {
+    down_cast<Arm64Assembler*>(GetAssembler())->Comment("Unreachable");
+    __ Brk(0);    // TODO: Introduce special markers for such code locations.
+  }
+}
+
+void LocationsBuilderARM64::VisitGoto(HGoto* got) {
+  got->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorARM64::VisitGoto(HGoto* got) {
+  HBasicBlock* successor = got->GetSuccessor();
+  // TODO: Support for suspend checks emission.
+  if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
+    __ B(codegen_->GetLabelOf(successor));
+  }
+}
+
+void LocationsBuilderARM64::VisitIf(HIf* if_instr) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
+  HInstruction* cond = if_instr->InputAt(0);
+  DCHECK(cond->IsCondition());
+  if (cond->AsCondition()->NeedsMaterialization()) {
+    locations->SetInAt(0, Location::RequiresRegister());
+  }
+}
+
+void InstructionCodeGeneratorARM64::VisitIf(HIf* if_instr) {
+  HInstruction* cond = if_instr->InputAt(0);
+  DCHECK(cond->IsCondition());
+  HCondition* condition = cond->AsCondition();
+  vixl::Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
+  vixl::Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
+
+  // TODO: Support constant condition input in VisitIf.
+
+  if (condition->NeedsMaterialization()) {
+    // The condition instruction has been materialized, compare the output to 0.
+    Location cond_val = if_instr->GetLocations()->InAt(0);
+    DCHECK(cond_val.IsRegister());
+    __ Cbnz(InputRegisterAt(if_instr, 0), true_target);
+
+  } else {
+    // The condition instruction has not been materialized, use its inputs as
+    // the comparison and its condition as the branch condition.
+    Register lhs = InputRegisterAt(condition, 0);
+    Operand rhs = InputOperandAt(condition, 1);
+    Condition cond = ARM64Condition(condition->GetCondition());
+    if ((cond == eq || cond == ne) && rhs.IsImmediate() && (rhs.immediate() == 0)) {
+      if (cond == eq) {
+        __ Cbz(lhs, true_target);
+      } else {
+        __ Cbnz(lhs, true_target);
+      }
+    } else {
+      __ Cmp(lhs, rhs);
+      __ B(cond, true_target);
+    }
+  }
+
+  if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
+    __ B(false_target);
+  }
+}
+
+void LocationsBuilderARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
+  Primitive::Type res_type = instruction->GetType();
+  Register res = OutputRegister(instruction);
+  Register obj = InputRegisterAt(instruction, 0);
+  uint32_t offset = instruction->GetFieldOffset().Uint32Value();
+
+  switch (res_type) {
+    case Primitive::kPrimBoolean: {
+      __ Ldrb(res, MemOperand(obj, offset));
+      break;
+    }
+    case Primitive::kPrimByte: {
+      __ Ldrsb(res, MemOperand(obj, offset));
+      break;
+    }
+    case Primitive::kPrimShort: {
+      __ Ldrsh(res, MemOperand(obj, offset));
+      break;
+    }
+    case Primitive::kPrimChar: {
+      __ Ldrh(res, MemOperand(obj, offset));
+      break;
+    }
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot:
+    case Primitive::kPrimLong: {  // TODO: support volatile.
+      DCHECK(res.IsX() == (res_type == Primitive::kPrimLong));
+      __ Ldr(res, MemOperand(obj, offset));
+      break;
+    }
+
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      LOG(FATAL) << "Unimplemented register res_type " << res_type;
+      break;
+
+    case Primitive::kPrimVoid:
+      LOG(FATAL) << "Unreachable res_type " << res_type;
+  }
+}
+
+void LocationsBuilderARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
+  Register obj = InputRegisterAt(instruction, 0);
+  Register value = InputRegisterAt(instruction, 1);
+  Primitive::Type field_type = instruction->InputAt(1)->GetType();
+  uint32_t offset = instruction->GetFieldOffset().Uint32Value();
+
+  switch (field_type) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte: {
+      __ Strb(value, MemOperand(obj, offset));
+      break;
+    }
+
+    case Primitive::kPrimShort:
+    case Primitive::kPrimChar: {
+      __ Strh(value, MemOperand(obj, offset));
+      break;
+    }
+
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot:
+    case Primitive::kPrimLong: {
+      DCHECK(value.IsX() == (field_type == Primitive::kPrimLong));
+      __ Str(value, MemOperand(obj, offset));
+
+      if (field_type == Primitive::kPrimNot) {
+        codegen_->MarkGCCard(obj, value);
+      }
+      break;
+    }
+
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      LOG(FATAL) << "Unimplemented register type " << field_type;
+      break;
+
+    case Primitive::kPrimVoid:
+      LOG(FATAL) << "Unreachable type " << field_type;
+  }
+}
+
+void LocationsBuilderARM64::VisitIntConstant(HIntConstant* constant) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
+  locations->SetOut(Location::ConstantLocation(constant));
+}
+
+void InstructionCodeGeneratorARM64::VisitIntConstant(HIntConstant* constant) {
+  // Will be generated at use site.
+}
+
+void LocationsBuilderARM64::VisitInvokeStatic(HInvokeStatic* invoke) {
+  HandleInvoke(invoke);
+}
+
+void LocationsBuilderARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
+  HandleInvoke(invoke);
+}
+
+void LocationsBuilderARM64::HandleInvoke(HInvoke* invoke) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
+  locations->AddTemp(LocationFrom(x0));
+
+  InvokeDexCallingConventionVisitor calling_convention_visitor;
+  for (size_t i = 0; i < invoke->InputCount(); i++) {
+    HInstruction* input = invoke->InputAt(i);
+    locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
+  }
+
+  Primitive::Type return_type = invoke->GetType();
+  if (return_type != Primitive::kPrimVoid) {
+    locations->SetOut(calling_convention_visitor.GetReturnLocation(return_type));
+  }
+}
+
+void InstructionCodeGeneratorARM64::VisitInvokeStatic(HInvokeStatic* invoke) {
+  Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0));
+  // Make sure that ArtMethod* is passed in W0 as per the calling convention
+  DCHECK(temp.Is(w0));
+  size_t index_in_cache = mirror::Array::DataOffset(kHeapRefSize).SizeValue() +
+    invoke->GetIndexInDexCache() * kHeapRefSize;
+
+  // TODO: Implement all kinds of calls:
+  // 1) boot -> boot
+  // 2) app -> boot
+  // 3) app -> app
+  //
+  // Currently we implement the app -> app logic, which looks up in the resolve cache.
+
+  // temp = method;
+  __ Ldr(temp, MemOperand(sp, kCurrentMethodStackOffset));
+  // temp = temp->dex_cache_resolved_methods_;
+  __ Ldr(temp, MemOperand(temp.X(), mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
+  // temp = temp[index_in_cache];
+  __ Ldr(temp, MemOperand(temp.X(), index_in_cache));
+  // lr = temp->entry_point_from_quick_compiled_code_;
+  __ Ldr(lr, MemOperand(temp.X(), mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
+  // lr();
+  __ Blr(lr);
+
+  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
+  DCHECK(!codegen_->IsLeafMethod());
+}
+
+void InstructionCodeGeneratorARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
+  LocationSummary* locations = invoke->GetLocations();
+  Location receiver = locations->InAt(0);
+  Register temp = XRegisterFrom(invoke->GetLocations()->GetTemp(0));
+  size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
+    invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
+  Offset class_offset = mirror::Object::ClassOffset();
+  Offset entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset();
+
+  // temp = object->GetClass();
+  if (receiver.IsStackSlot()) {
+    __ Ldr(temp.W(), MemOperand(sp, receiver.GetStackIndex()));
+    __ Ldr(temp.W(), MemOperand(temp, class_offset.SizeValue()));
+  } else {
+    DCHECK(receiver.IsRegister());
+    __ Ldr(temp.W(), HeapOperandFrom(receiver, Primitive::kPrimNot,
+                                     class_offset));
+  }
+  // temp = temp->GetMethodAt(method_offset);
+  __ Ldr(temp.W(), MemOperand(temp, method_offset));
+  // lr = temp->GetEntryPoint();
+  __ Ldr(lr, MemOperand(temp, entry_point.SizeValue()));
+  // lr();
+  __ Blr(lr);
+  DCHECK(!codegen_->IsLeafMethod());
+  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
+}
+
+void LocationsBuilderARM64::VisitLoadLocal(HLoadLocal* load) {
+  load->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorARM64::VisitLoadLocal(HLoadLocal* load) {
+  // Nothing to do, this is driven by the code generator.
+}
+
+void LocationsBuilderARM64::VisitLocal(HLocal* local) {
+  local->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorARM64::VisitLocal(HLocal* local) {
+  DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
+}
+
+void LocationsBuilderARM64::VisitLongConstant(HLongConstant* constant) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
+  locations->SetOut(Location::ConstantLocation(constant));
+}
+
+void InstructionCodeGeneratorARM64::VisitLongConstant(HLongConstant* constant) {
+  // Will be generated at use site.
+}
+
+void LocationsBuilderARM64::VisitNewInstance(HNewInstance* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+  InvokeRuntimeCallingConvention calling_convention;
+  locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(0)));
+  locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(1)));
+  locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
+}
+
+void InstructionCodeGeneratorARM64::VisitNewInstance(HNewInstance* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt);
+  DCHECK(type_index.Is(w0));
+  Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimNot);
+  DCHECK(current_method.Is(w1));
+  __ Ldr(current_method, MemOperand(sp, kCurrentMethodStackOffset));
+  __ Mov(type_index, instruction->GetTypeIndex());
+  __ Ldr(lr, MemOperand(tr, QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, pAllocObjectWithAccessCheck).Int32Value()));
+  __ Blr(lr);
+  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+  DCHECK(!codegen_->IsLeafMethod());
+}
+
+void LocationsBuilderARM64::VisitNot(HNot* instruction) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorARM64::VisitNot(HNot* instruction) {
+  switch (instruction->InputAt(0)->GetType()) {
+    case Primitive::kPrimBoolean:
+      __ Eor(OutputRegister(instruction), InputRegisterAt(instruction, 0), Operand(1));
+      break;
+
+    case Primitive::kPrimInt:
+      __ Mvn(OutputRegister(instruction), InputOperandAt(instruction, 0));
+      break;
+
+    case Primitive::kPrimLong:
+      LOG(FATAL) << "Not yet implemented type for not operation " << instruction->GetResultType();
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected type for not operation " << instruction->GetResultType();
+  }
+}
+
+void LocationsBuilderARM64::VisitNullCheck(HNullCheck* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetInAt(0, Location::RequiresRegister());
+  if (instruction->HasUses()) {
+    locations->SetOut(Location::SameAsFirstInput());
+  }
+}
+
+void InstructionCodeGeneratorARM64::VisitNullCheck(HNullCheck* instruction) {
+  SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM64(instruction);
+  codegen_->AddSlowPath(slow_path);
+
+  LocationSummary* locations = instruction->GetLocations();
+  Location obj = locations->InAt(0);
+  if (obj.IsRegister()) {
+    __ Cbz(RegisterFrom(obj, instruction->InputAt(0)->GetType()), slow_path->GetEntryLabel());
+  } else {
+    DCHECK(obj.IsConstant()) << obj;
+    DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
+    __ B(slow_path->GetEntryLabel());
+  }
+}
+
+void LocationsBuilderARM64::VisitParameterValue(HParameterValue* instruction) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+  Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
+  if (location.IsStackSlot()) {
+    location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
+  } else if (location.IsDoubleStackSlot()) {
+    location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
+  }
+  locations->SetOut(location);
+}
+
+void InstructionCodeGeneratorARM64::VisitParameterValue(HParameterValue* instruction) {
+  // Nothing to do, the parameter is already at its location.
+}
+
+void LocationsBuilderARM64::VisitPhi(HPhi* instruction) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+  for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
+    locations->SetInAt(i, Location::Any());
+  }
+  locations->SetOut(Location::Any());
+}
+
+void InstructionCodeGeneratorARM64::VisitPhi(HPhi* instruction) {
+  LOG(FATAL) << "Unreachable";
+}
+
+void LocationsBuilderARM64::VisitReturn(HReturn* instruction) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+  Primitive::Type return_type = instruction->InputAt(0)->GetType();
+
+  if (return_type == Primitive::kPrimFloat || return_type == Primitive::kPrimDouble) {
+    LOG(FATAL) << "Unimplemented return type " << return_type;
+  }
+
+  locations->SetInAt(0, LocationFrom(x0));
+}
+
+void InstructionCodeGeneratorARM64::VisitReturn(HReturn* instruction) {
+  if (kIsDebugBuild) {
+    Primitive::Type type = instruction->InputAt(0)->GetType();
+    switch (type) {
+      case Primitive::kPrimBoolean:
+      case Primitive::kPrimByte:
+      case Primitive::kPrimChar:
+      case Primitive::kPrimShort:
+      case Primitive::kPrimInt:
+      case Primitive::kPrimNot:
+        DCHECK(InputRegisterAt(instruction, 0).Is(w0));
+        break;
+
+      case Primitive::kPrimLong:
+        DCHECK(InputRegisterAt(instruction, 0).Is(x0));
+        break;
+
+      default:
+        LOG(FATAL) << "Unimplemented return type " << type;
+    }
+  }
+  codegen_->GenerateFrameExit();
+  __ Br(lr);
+}
+
+void LocationsBuilderARM64::VisitReturnVoid(HReturnVoid* instruction) {
+  instruction->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorARM64::VisitReturnVoid(HReturnVoid* instruction) {
+  codegen_->GenerateFrameExit();
+  __ Br(lr);
+}
+
+void LocationsBuilderARM64::VisitStoreLocal(HStoreLocal* store) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
+  Primitive::Type field_type = store->InputAt(1)->GetType();
+  switch (field_type) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot:
+      locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
+      break;
+
+    case Primitive::kPrimLong:
+      locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
+      break;
+
+    default:
+      LOG(FATAL) << "Unimplemented local type " << field_type;
+  }
+}
+
+void InstructionCodeGeneratorARM64::VisitStoreLocal(HStoreLocal* store) {
+}
+
+void LocationsBuilderARM64::VisitSub(HSub* instruction) {
+  HandleAddSub(instruction);
+}
+
+void InstructionCodeGeneratorARM64::VisitSub(HSub* instruction) {
+  HandleAddSub(instruction);
+}
+
+void LocationsBuilderARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+  if (instruction->HasUses()) {
+    locations->SetOut(Location::SameAsFirstInput());
+  }
+}
+
+void InstructionCodeGeneratorARM64::VisitBoundsCheck(HBoundsCheck* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  BoundsCheckSlowPathARM64* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM64(
+      instruction, locations->InAt(0), locations->InAt(1));
+  codegen_->AddSlowPath(slow_path);
+
+  __ Cmp(InputRegisterAt(instruction, 0), InputOperandAt(instruction, 1));
+  __ B(slow_path->GetEntryLabel(), hs);
+}
+
+void LocationsBuilderARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
+  new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
+}
+
+void InstructionCodeGeneratorARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
+  // TODO: Improve support for suspend checks.
+  SuspendCheckSlowPathARM64* slow_path =
+      new (GetGraph()->GetArena()) SuspendCheckSlowPathARM64(instruction, nullptr);
+  codegen_->AddSlowPath(slow_path);
+
+  __ Subs(wSuspend, wSuspend, 1);
+  __ B(slow_path->GetEntryLabel(), le);
+  __ Bind(slow_path->GetReturnLabel());
+}
+
+void LocationsBuilderARM64::VisitTemporary(HTemporary* temp) {
+  temp->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorARM64::VisitTemporary(HTemporary* temp) {
+  // Nothing to do, this is driven by the code generator.
+}
+
+}  // namespace arm64
+}  // namespace art
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
new file mode 100644
index 0000000..a4003ff
--- /dev/null
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2014 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_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM64_H_
+#define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM64_H_
+
+#include "code_generator.h"
+#include "nodes.h"
+#include "parallel_move_resolver.h"
+#include "utils/arm64/assembler_arm64.h"
+#include "a64/disasm-a64.h"
+#include "a64/macro-assembler-a64.h"
+#include "arch/arm64/quick_method_frame_info_arm64.h"
+
+namespace art {
+namespace arm64 {
+
+class CodeGeneratorARM64;
+
+static constexpr size_t kArm64WordSize = 8;
+static const vixl::Register kParameterCoreRegisters[] = {
+  vixl::x1, vixl::x2, vixl::x3, vixl::x4, vixl::x5, vixl::x6, vixl::x7
+};
+static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
+static const vixl::FPRegister kParameterFPRegisters[] = {
+  vixl::d0, vixl::d1, vixl::d2, vixl::d3, vixl::d4, vixl::d5, vixl::d6, vixl::d7
+};
+static constexpr size_t kParameterFPRegistersLength = arraysize(kParameterFPRegisters);
+
+const vixl::Register tr = vixl::x18;        // Thread Register
+const vixl::Register wSuspend = vixl::w19;  // Suspend Register
+const vixl::Register xSuspend = vixl::x19;
+
+const vixl::CPURegList vixl_reserved_core_registers(vixl::ip0, vixl::ip1);
+const vixl::CPURegList runtime_reserved_core_registers(tr, xSuspend, vixl::lr);
+const vixl::CPURegList quick_callee_saved_registers(vixl::CPURegister::kRegister,
+                                                    vixl::kXRegSize,
+                                                    kArm64CalleeSaveRefSpills);
+
+class InvokeDexCallingConvention : public CallingConvention<vixl::Register, vixl::FPRegister> {
+ public:
+  InvokeDexCallingConvention()
+      : CallingConvention(kParameterCoreRegisters,
+                          kParameterCoreRegistersLength,
+                          kParameterFPRegisters,
+                          kParameterFPRegistersLength) {}
+
+  Location GetReturnLocation(Primitive::Type return_type) {
+    DCHECK_NE(return_type, Primitive::kPrimVoid);
+    if (return_type == Primitive::kPrimFloat || return_type == Primitive::kPrimDouble) {
+      LOG(FATAL) << "Unimplemented return type " << return_type;
+    }
+    return Location::RegisterLocation(X0);
+  }
+
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
+};
+
+class InvokeDexCallingConventionVisitor {
+ public:
+  InvokeDexCallingConventionVisitor() : gp_index_(0), stack_index_(0) {}
+
+  Location GetNextLocation(Primitive::Type type);
+  Location GetReturnLocation(Primitive::Type return_type) {
+    return calling_convention.GetReturnLocation(return_type);
+  }
+
+ private:
+  InvokeDexCallingConvention calling_convention;
+  // The current index for core registers.
+  uint32_t gp_index_;
+  // The current stack index.
+  uint32_t stack_index_;
+
+  DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitor);
+};
+
+class InstructionCodeGeneratorARM64 : public HGraphVisitor {
+ public:
+  InstructionCodeGeneratorARM64(HGraph* graph, CodeGeneratorARM64* codegen);
+
+#define DECLARE_VISIT_INSTRUCTION(name, super) \
+  virtual void Visit##name(H##name* instr);
+  FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
+#undef DECLARE_VISIT_INSTRUCTION
+
+  void LoadCurrentMethod(XRegister reg);
+
+  Arm64Assembler* GetAssembler() const { return assembler_; }
+
+ private:
+  void HandleAddSub(HBinaryOperation* instr);
+
+  Arm64Assembler* const assembler_;
+  CodeGeneratorARM64* const codegen_;
+
+  DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorARM64);
+};
+
+class LocationsBuilderARM64 : public HGraphVisitor {
+ public:
+  explicit LocationsBuilderARM64(HGraph* graph, CodeGeneratorARM64* codegen)
+      : HGraphVisitor(graph), codegen_(codegen) {}
+
+#define DECLARE_VISIT_INSTRUCTION(name, super) \
+  virtual void Visit##name(H##name* instr);
+  FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
+#undef DECLARE_VISIT_INSTRUCTION
+
+ private:
+  void HandleAddSub(HBinaryOperation* instr);
+  void HandleInvoke(HInvoke* instr);
+
+  CodeGeneratorARM64* const codegen_;
+  InvokeDexCallingConventionVisitor parameter_visitor_;
+
+  DISALLOW_COPY_AND_ASSIGN(LocationsBuilderARM64);
+};
+
+class CodeGeneratorARM64 : public CodeGenerator {
+ public:
+  explicit CodeGeneratorARM64(HGraph* graph);
+  virtual ~CodeGeneratorARM64() { }
+
+  virtual void GenerateFrameEntry() OVERRIDE;
+  virtual void GenerateFrameExit() OVERRIDE;
+
+  static const vixl::CPURegList& GetFramePreservedRegisters() {
+    static const vixl::CPURegList frame_preserved_regs =
+        vixl::CPURegList(vixl::CPURegister::kRegister, vixl::kXRegSize, vixl::lr.Bit());
+    return frame_preserved_regs;
+  }
+  static int GetFramePreservedRegistersSize() {
+    return GetFramePreservedRegisters().TotalSizeInBytes();
+  }
+
+  virtual void Bind(HBasicBlock* block) OVERRIDE;
+
+  vixl::Label* GetLabelOf(HBasicBlock* block) const {
+    return block_labels_ + block->GetBlockId();
+  }
+
+  virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
+
+  virtual size_t GetWordSize() const OVERRIDE {
+    return kArm64WordSize;
+  }
+
+  virtual size_t FrameEntrySpillSize() const OVERRIDE;
+
+  virtual HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; }
+  virtual HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; }
+  virtual Arm64Assembler* GetAssembler() OVERRIDE { return &assembler_; }
+
+  // Emit a write barrier.
+  void MarkGCCard(vixl::Register object, vixl::Register value);
+
+  // Register allocation.
+
+  virtual void SetupBlockedRegisters() const OVERRIDE;
+  // AllocateFreeRegister() is only used when allocating registers locally
+  // during CompileBaseline().
+  virtual Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
+
+  virtual Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
+
+  virtual size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE {
+    UNIMPLEMENTED(INFO) << "TODO: SaveCoreRegister";
+    return 0;
+  }
+
+  virtual size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE {
+    UNIMPLEMENTED(INFO) << "TODO: RestoreCoreRegister";
+    return 0;
+  }
+
+  // The number of registers that can be allocated. The register allocator may
+  // decide to reserve and not use a few of them.
+  // We do not consider registers sp, xzr, wzr. They are either not allocatable
+  // (xzr, wzr), or make for poor allocatable registers (sp alignment
+  // requirements, etc.). This also facilitates our task as all other registers
+  // can easily be mapped via to or from their type and index or code.
+  static const int kNumberOfAllocatableCoreRegisters = vixl::kNumberOfRegisters - 1;
+  static const int kNumberOfAllocatableFloatingPointRegisters = vixl::kNumberOfFPRegisters;
+  static const int kNumberOfAllocatableRegisters =
+      kNumberOfAllocatableCoreRegisters + kNumberOfAllocatableFloatingPointRegisters;
+  static constexpr int kNumberOfAllocatableRegisterPairs = 0;
+
+  virtual void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
+  virtual void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
+
+  virtual InstructionSet GetInstructionSet() const OVERRIDE {
+    return InstructionSet::kArm64;
+  }
+
+  void MoveHelper(Location destination, Location source, Primitive::Type type);
+
+  virtual void Initialize() OVERRIDE {
+    HGraph* graph = GetGraph();
+    int length = graph->GetBlocks().Size();
+    block_labels_ = graph->GetArena()->AllocArray<vixl::Label>(length);
+    for (int i = 0; i < length; ++i) {
+      new(block_labels_ + i) vixl::Label();
+    }
+  }
+
+ private:
+  // Labels for each block that will be compiled.
+  vixl::Label* block_labels_;
+
+  LocationsBuilderARM64 location_builder_;
+  InstructionCodeGeneratorARM64 instruction_visitor_;
+  Arm64Assembler assembler_;
+
+  DISALLOW_COPY_AND_ASSIGN(CodeGeneratorARM64);
+};
+
+}  // namespace arm64
+}  // namespace art
+
+#endif  // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM64_H_
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 73143d6..61f0750 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -56,7 +56,21 @@
 
 #define __ reinterpret_cast<X86Assembler*>(codegen->GetAssembler())->
 
-class NullCheckSlowPathX86 : public SlowPathCode {
+class SlowPathCodeX86 : public SlowPathCode {
+ public:
+  SlowPathCodeX86() : entry_label_(), exit_label_() {}
+
+  Label* GetEntryLabel() { return &entry_label_; }
+  Label* GetExitLabel() { return &exit_label_; }
+
+ private:
+  Label entry_label_;
+  Label exit_label_;
+
+  DISALLOW_COPY_AND_ASSIGN(SlowPathCodeX86);
+};
+
+class NullCheckSlowPathX86 : public SlowPathCodeX86 {
  public:
   explicit NullCheckSlowPathX86(HNullCheck* instruction) : instruction_(instruction) {}
 
@@ -71,7 +85,7 @@
   DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86);
 };
 
-class StackOverflowCheckSlowPathX86 : public SlowPathCode {
+class StackOverflowCheckSlowPathX86 : public SlowPathCodeX86 {
  public:
   StackOverflowCheckSlowPathX86() {}
 
@@ -86,7 +100,7 @@
   DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathX86);
 };
 
-class BoundsCheckSlowPathX86 : public SlowPathCode {
+class BoundsCheckSlowPathX86 : public SlowPathCodeX86 {
  public:
   BoundsCheckSlowPathX86(HBoundsCheck* instruction,
                          Location index_location,
@@ -94,7 +108,7 @@
       : instruction_(instruction), index_location_(index_location), length_location_(length_location) {}
 
   virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
-    CodeGeneratorX86* x86_codegen = reinterpret_cast<CodeGeneratorX86*>(codegen);
+    CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
     __ Bind(GetEntryLabel());
     InvokeRuntimeCallingConvention calling_convention;
     x86_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), index_location_);
@@ -111,12 +125,13 @@
   DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86);
 };
 
-class SuspendCheckSlowPathX86 : public SlowPathCode {
+class SuspendCheckSlowPathX86 : public SlowPathCodeX86 {
  public:
   explicit SuspendCheckSlowPathX86(HSuspendCheck* instruction, HBasicBlock* successor)
       : instruction_(instruction), successor_(successor) {}
 
   virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
     __ Bind(GetEntryLabel());
     codegen->SaveLiveRegisters(instruction_->GetLocations());
     __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pTestSuspend)));
@@ -125,7 +140,7 @@
     if (successor_ == nullptr) {
       __ jmp(GetReturnLabel());
     } else {
-      __ jmp(codegen->GetLabelOf(successor_));
+      __ jmp(x86_codegen->GetLabelOf(successor_));
     }
   }
 
@@ -167,16 +182,19 @@
   stream << X86ManagedRegister::FromXmmRegister(XmmRegister(reg));
 }
 
-void CodeGeneratorX86::SaveCoreRegister(Location stack_location, uint32_t reg_id) {
-  __ movl(Address(ESP, stack_location.GetStackIndex()), static_cast<Register>(reg_id));
+size_t CodeGeneratorX86::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
+  __ movl(Address(ESP, stack_index), static_cast<Register>(reg_id));
+  return kX86WordSize;
 }
 
-void CodeGeneratorX86::RestoreCoreRegister(Location stack_location, uint32_t reg_id) {
-  __ movl(static_cast<Register>(reg_id), Address(ESP, stack_location.GetStackIndex()));
+size_t CodeGeneratorX86::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
+  __ movl(static_cast<Register>(reg_id), Address(ESP, stack_index));
+  return kX86WordSize;
 }
 
 CodeGeneratorX86::CodeGeneratorX86(HGraph* graph)
     : CodeGenerator(graph, kNumberOfCpuRegisters, kNumberOfXmmRegisters, kNumberOfRegisterPairs),
+      block_labels_(graph->GetArena(), 0),
       location_builder_(graph, this),
       instruction_visitor_(graph, this),
       move_resolver_(graph->GetArena(), this) {}
@@ -191,19 +209,11 @@
       size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
       X86ManagedRegister pair =
           X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
+      DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
+      DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
       blocked_core_registers_[pair.AsRegisterPairLow()] = true;
       blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
-      // Block all other register pairs that share a register with `pair`.
-      for (int i = 0; i < kNumberOfRegisterPairs; i++) {
-        X86ManagedRegister current =
-            X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
-        if (current.AsRegisterPairLow() == pair.AsRegisterPairLow()
-            || current.AsRegisterPairLow() == pair.AsRegisterPairHigh()
-            || current.AsRegisterPairHigh() == pair.AsRegisterPairLow()
-            || current.AsRegisterPairHigh() == pair.AsRegisterPairHigh()) {
-          blocked_register_pairs_[i] = true;
-        }
-      }
+      UpdateBlockedPairRegisters();
       return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
     }
 
@@ -250,10 +260,19 @@
   blocked_core_registers_[EBP] = true;
   blocked_core_registers_[ESI] = true;
   blocked_core_registers_[EDI] = true;
-  blocked_register_pairs_[EAX_EDI] = true;
-  blocked_register_pairs_[EDX_EDI] = true;
-  blocked_register_pairs_[ECX_EDI] = true;
-  blocked_register_pairs_[EBX_EDI] = true;
+
+  UpdateBlockedPairRegisters();
+}
+
+void CodeGeneratorX86::UpdateBlockedPairRegisters() const {
+  for (int i = 0; i < kNumberOfRegisterPairs; i++) {
+    X86ManagedRegister current =
+        X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
+    if (blocked_core_registers_[current.AsRegisterPairLow()]
+        || blocked_core_registers_[current.AsRegisterPairHigh()]) {
+      blocked_register_pairs_[i] = true;
+    }
+  }
 }
 
 InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen)
@@ -276,7 +295,7 @@
   __ subl(ESP, Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86WordSize));
 
   if (!skip_overflow_check && kExplicitStackOverflowCheck) {
-    SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86();
+    SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86();
     AddSlowPath(slow_path);
 
     __ fs()->cmpl(ESP, Address::Absolute(Thread::StackEndOffset<kX86WordSize>()));
@@ -290,8 +309,8 @@
   __ addl(ESP, Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86WordSize));
 }
 
-void CodeGeneratorX86::Bind(Label* label) {
-  __ Bind(label);
+void CodeGeneratorX86::Bind(HBasicBlock* block) {
+  __ Bind(GetLabelOf(block));
 }
 
 void InstructionCodeGeneratorX86::LoadCurrentMethod(Register reg) {
@@ -468,23 +487,29 @@
 }
 
 void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
-  if (instruction->AsIntConstant() != nullptr) {
+  if (instruction->IsIntConstant()) {
     Immediate imm(instruction->AsIntConstant()->GetValue());
     if (location.IsRegister()) {
       __ movl(location.As<Register>(), imm);
-    } else {
+    } else if (location.IsStackSlot()) {
       __ movl(Address(ESP, location.GetStackIndex()), imm);
+    } else {
+      DCHECK(location.IsConstant());
+      DCHECK_EQ(location.GetConstant(), instruction);
     }
-  } else if (instruction->AsLongConstant() != nullptr) {
+  } else if (instruction->IsLongConstant()) {
     int64_t value = instruction->AsLongConstant()->GetValue();
     if (location.IsRegister()) {
       __ movl(location.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
       __ movl(location.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
-    } else {
+    } else if (location.IsDoubleStackSlot()) {
       __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value)));
       __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)), Immediate(High32Bits(value)));
+    } else {
+      DCHECK(location.IsConstant());
+      DCHECK_EQ(location.GetConstant(), instruction);
     }
-  } else if (instruction->AsLoadLocal() != nullptr) {
+  } else if (instruction->IsLoadLocal()) {
     int slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
     switch (instruction->GetType()) {
       case Primitive::kPrimBoolean:
@@ -571,48 +596,66 @@
       new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
   HInstruction* cond = if_instr->InputAt(0);
   if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
-    locations->SetInAt(0, Location::Any(), Location::kDiesAtEntry);
+    locations->SetInAt(0, Location::Any());
   }
 }
 
 void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) {
   HInstruction* cond = if_instr->InputAt(0);
-  bool materialized = !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
-  // Moves do not affect the eflags register, so if the condition is evaluated
-  // just before the if, we don't need to evaluate it again.
-  bool eflags_set = cond->IsCondition()
-      && cond->AsCondition()->IsBeforeWhenDisregardMoves(if_instr);
-  if (materialized) {
-    if (!eflags_set) {
-      // Materialized condition, compare against 0.
-      Location lhs = if_instr->GetLocations()->InAt(0);
-      if (lhs.IsRegister()) {
-        __ cmpl(lhs.As<Register>(), Immediate(0));
-      } else {
-        __ cmpl(Address(ESP, lhs.GetStackIndex()), Immediate(0));
+  if (cond->IsIntConstant()) {
+    // Constant condition, statically compared against 1.
+    int32_t cond_value = cond->AsIntConstant()->GetValue();
+    if (cond_value == 1) {
+      if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
+                                     if_instr->IfTrueSuccessor())) {
+        __ jmp(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
       }
-      __ j(kNotEqual,  codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
+      return;
     } else {
+      DCHECK_EQ(cond_value, 0);
+    }
+  } else {
+    bool materialized =
+        !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
+    // Moves do not affect the eflags register, so if the condition is
+    // evaluated just before the if, we don't need to evaluate it
+    // again.
+    bool eflags_set = cond->IsCondition()
+        && cond->AsCondition()->IsBeforeWhenDisregardMoves(if_instr);
+    if (materialized) {
+      if (!eflags_set) {
+        // Materialized condition, compare against 0.
+        Location lhs = if_instr->GetLocations()->InAt(0);
+        if (lhs.IsRegister()) {
+          __ cmpl(lhs.As<Register>(), Immediate(0));
+        } else {
+          __ cmpl(Address(ESP, lhs.GetStackIndex()), Immediate(0));
+        }
+        __ j(kNotEqual,  codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
+      } else {
+        __ j(X86Condition(cond->AsCondition()->GetCondition()),
+             codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
+      }
+    } else {
+      Location lhs = cond->GetLocations()->InAt(0);
+      Location rhs = cond->GetLocations()->InAt(1);
+      // LHS is guaranteed to be in a register (see
+      // LocationsBuilderX86::VisitCondition).
+      if (rhs.IsRegister()) {
+        __ cmpl(lhs.As<Register>(), rhs.As<Register>());
+      } else if (rhs.IsConstant()) {
+        HIntConstant* instruction = rhs.GetConstant()->AsIntConstant();
+        Immediate imm(instruction->AsIntConstant()->GetValue());
+        __ cmpl(lhs.As<Register>(), imm);
+      } else {
+        __ cmpl(lhs.As<Register>(), Address(ESP, rhs.GetStackIndex()));
+      }
       __ j(X86Condition(cond->AsCondition()->GetCondition()),
            codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
     }
-  } else {
-    Location lhs = cond->GetLocations()->InAt(0);
-    Location rhs = cond->GetLocations()->InAt(1);
-    // LHS is guaranteed to be in a register (see LocationsBuilderX86::VisitCondition).
-    if (rhs.IsRegister()) {
-      __ cmpl(lhs.As<Register>(), rhs.As<Register>());
-    } else if (rhs.IsConstant()) {
-      HIntConstant* instruction = rhs.GetConstant()->AsIntConstant();
-      Immediate imm(instruction->AsIntConstant()->GetValue());
-      __ cmpl(lhs.As<Register>(), imm);
-    } else {
-      __ cmpl(lhs.As<Register>(), Address(ESP, rhs.GetStackIndex()));
-    }
-    __ j(X86Condition(cond->AsCondition()->GetCondition()),
-         codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
   }
-  if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
+  if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
+                                 if_instr->IfFalseSuccessor())) {
     __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
   }
 }
@@ -664,8 +707,8 @@
 void LocationsBuilderX86::VisitCondition(HCondition* comp) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
-  locations->SetInAt(1, Location::Any(), Location::kDiesAtEntry);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::Any());
   if (comp->NeedsMaterialization()) {
     locations->SetOut(Location::RequiresRegister());
   }
@@ -747,6 +790,7 @@
 }
 
 void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant) {
+  // Will be generated at use site.
 }
 
 void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
@@ -759,6 +803,26 @@
   // Will be generated at use site.
 }
 
+void LocationsBuilderX86::VisitFloatConstant(HFloatConstant* constant) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
+  locations->SetOut(Location::ConstantLocation(constant));
+}
+
+void InstructionCodeGeneratorX86::VisitFloatConstant(HFloatConstant* constant) {
+  // Will be generated at use site.
+}
+
+void LocationsBuilderX86::VisitDoubleConstant(HDoubleConstant* constant) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
+  locations->SetOut(Location::ConstantLocation(constant));
+}
+
+void InstructionCodeGeneratorX86::VisitDoubleConstant(HDoubleConstant* constant) {
+  // Will be generated at use site.
+}
+
 void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) {
   ret->SetLocations(nullptr);
 }
@@ -921,6 +985,47 @@
   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
 }
 
+void LocationsBuilderX86::VisitNeg(HNeg* neg) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
+  switch (neg->GetResultType()) {
+    case Primitive::kPrimInt:
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetOut(Location::SameAsFirstInput());
+      break;
+
+    case Primitive::kPrimLong:
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
+  }
+}
+
+void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) {
+  LocationSummary* locations = neg->GetLocations();
+  Location out = locations->Out();
+  Location in = locations->InAt(0);
+  switch (neg->GetResultType()) {
+    case Primitive::kPrimInt:
+      DCHECK(in.IsRegister());
+      __ negl(out.As<Register>());
+      break;
+
+    case Primitive::kPrimLong:
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
+  }
+}
+
 void LocationsBuilderX86::VisitAdd(HAdd* add) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
@@ -951,16 +1056,13 @@
   LocationSummary* locations = add->GetLocations();
   Location first = locations->InAt(0);
   Location second = locations->InAt(1);
-
+  DCHECK(first.Equals(locations->Out()));
   switch (add->GetResultType()) {
     case Primitive::kPrimInt: {
-      DCHECK_EQ(first.As<Register>(), locations->Out().As<Register>());
       if (second.IsRegister()) {
         __ addl(first.As<Register>(), second.As<Register>());
       } else if (second.IsConstant()) {
-        HConstant* instruction = second.GetConstant();
-        Immediate imm(instruction->AsIntConstant()->GetValue());
-        __ addl(first.As<Register>(), imm);
+        __ addl(first.As<Register>(), Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
       } else {
         __ addl(first.As<Register>(), Address(ESP, second.GetStackIndex()));
       }
@@ -968,10 +1070,6 @@
     }
 
     case Primitive::kPrimLong: {
-      DCHECK_EQ(first.AsRegisterPairLow<Register>(),
-                locations->Out().AsRegisterPairLow<Register>());
-      DCHECK_EQ(first.AsRegisterPairHigh<Register>(),
-                locations->Out().AsRegisterPairHigh<Register>());
       if (second.IsRegister()) {
         __ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
         __ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
@@ -1017,16 +1115,16 @@
       locations->SetOut(Location::SameAsFirstInput());
       break;
     }
-
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetOut(Location::SameAsFirstInput());
       break;
+    }
 
     default:
-      LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
+      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
   }
 }
 
@@ -1034,52 +1132,153 @@
   LocationSummary* locations = sub->GetLocations();
   Location first = locations->InAt(0);
   Location second = locations->InAt(1);
+  DCHECK(first.Equals(locations->Out()));
   switch (sub->GetResultType()) {
     case Primitive::kPrimInt: {
-      DCHECK_EQ(first.As<Register>(),
-                locations->Out().As<Register>());
       if (second.IsRegister()) {
-        __ subl(first.As<Register>(),
-                second.As<Register>());
+        __ subl(first.As<Register>(), second.As<Register>());
       } else if (second.IsConstant()) {
-        HConstant* instruction = second.GetConstant();
-        Immediate imm(instruction->AsIntConstant()->GetValue());
-        __ subl(first.As<Register>(), imm);
+        __ subl(first.As<Register>(), Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
       } else {
-        __ subl(first.As<Register>(),
-                Address(ESP, second.GetStackIndex()));
+        __ subl(first.As<Register>(), Address(ESP, second.GetStackIndex()));
       }
       break;
     }
 
     case Primitive::kPrimLong: {
-      DCHECK_EQ(first.AsRegisterPairLow<Register>(),
-                locations->Out().AsRegisterPairLow<Register>());
-      DCHECK_EQ(first.AsRegisterPairHigh<Register>(),
-                locations->Out().AsRegisterPairHigh<Register>());
       if (second.IsRegister()) {
-        __ subl(first.AsRegisterPairLow<Register>(),
-                second.AsRegisterPairLow<Register>());
-        __ sbbl(first.AsRegisterPairHigh<Register>(),
-                second.AsRegisterPairHigh<Register>());
+        __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
+        __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
       } else {
-        __ subl(first.AsRegisterPairLow<Register>(),
-                Address(ESP, second.GetStackIndex()));
+        __ subl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
         __ sbbl(first.AsRegisterPairHigh<Register>(),
                 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
       }
       break;
     }
 
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
+    case Primitive::kPrimFloat: {
+      __ subss(first.As<XmmRegister>(), second.As<XmmRegister>());
       break;
+    }
+
+    case Primitive::kPrimDouble: {
+      __ subsd(first.As<XmmRegister>(), second.As<XmmRegister>());
+      break;
+    }
 
     default:
-      LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
+      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
+  }
+}
+
+void LocationsBuilderX86::VisitMul(HMul* mul) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
+  switch (mul->GetResultType()) {
+    case Primitive::kPrimInt:
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::Any());
+      locations->SetOut(Location::SameAsFirstInput());
+      break;
+    case Primitive::kPrimLong: {
+      locations->SetInAt(0, Location::RequiresRegister());
+      // TODO: Currently this handles only stack operands:
+      // - we don't have enough registers because we currently use Quick ABI.
+      // - by the time we have a working register allocator we will probably change the ABI
+      // and fix the above.
+      // - we don't have a way yet to request operands on stack but the base line compiler
+      // will leave the operands on the stack with Any().
+      locations->SetInAt(1, Location::Any());
+      locations->SetOut(Location::SameAsFirstInput());
+      // Needed for imul on 32bits with 64bits output.
+      locations->AddTemp(Location::RegisterLocation(EAX));
+      locations->AddTemp(Location::RegisterLocation(EDX));
+      break;
+    }
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetOut(Location::SameAsFirstInput());
+      break;
+    }
+
+    default:
+      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
+  }
+}
+
+void InstructionCodeGeneratorX86::VisitMul(HMul* mul) {
+  LocationSummary* locations = mul->GetLocations();
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
+  DCHECK(first.Equals(locations->Out()));
+
+  switch (mul->GetResultType()) {
+    case Primitive::kPrimInt: {
+      if (second.IsRegister()) {
+        __ imull(first.As<Register>(), second.As<Register>());
+      } else if (second.IsConstant()) {
+        Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
+        __ imull(first.As<Register>(), imm);
+      } else {
+        DCHECK(second.IsStackSlot());
+        __ imull(first.As<Register>(), Address(ESP, second.GetStackIndex()));
+      }
+      break;
+    }
+
+    case Primitive::kPrimLong: {
+      DCHECK(second.IsDoubleStackSlot());
+
+      Register in1_hi = first.AsRegisterPairHigh<Register>();
+      Register in1_lo = first.AsRegisterPairLow<Register>();
+      Address in2_hi(ESP, second.GetHighStackIndex(kX86WordSize));
+      Address in2_lo(ESP, second.GetStackIndex());
+      Register eax = locations->GetTemp(0).As<Register>();
+      Register edx = locations->GetTemp(1).As<Register>();
+
+      DCHECK_EQ(EAX, eax);
+      DCHECK_EQ(EDX, edx);
+
+      // input: in1 - 64 bits, in2 - 64 bits
+      // output: in1
+      // formula: in1.hi : in1.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
+      // parts: in1.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
+      // parts: in1.lo = (in1.lo * in2.lo)[31:0]
+
+      __ movl(eax, in2_hi);
+      // eax <- in1.lo * in2.hi
+      __ imull(eax, in1_lo);
+      // in1.hi <- in1.hi * in2.lo
+      __ imull(in1_hi, in2_lo);
+      // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
+      __ addl(in1_hi, eax);
+      // move in1_lo to eax to prepare for double precision
+      __ movl(eax, in1_lo);
+      // edx:eax <- in1.lo * in2.lo
+      __ mull(in2_lo);
+      // in1.hi <- in2.hi * in1.lo +  in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
+      __ addl(in1_hi, edx);
+      // in1.lo <- (in1.lo * in2.lo)[31:0];
+      __ movl(in1_lo, eax);
+
+      break;
+    }
+
+    case Primitive::kPrimFloat: {
+      __ mulss(first.As<XmmRegister>(), second.As<XmmRegister>());
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      __ mulsd(first.As<XmmRegister>(), second.As<XmmRegister>());
+      break;
+    }
+
+    default:
+      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
   }
 }
 
@@ -1104,6 +1303,28 @@
   DCHECK(!codegen_->IsLeafMethod());
 }
 
+void LocationsBuilderX86::VisitNewArray(HNewArray* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+  locations->SetOut(Location::RegisterLocation(EAX));
+  InvokeRuntimeCallingConvention calling_convention;
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
+}
+
+void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
+  InvokeRuntimeCallingConvention calling_convention;
+  LoadCurrentMethod(calling_convention.GetRegisterAt(1));
+  __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
+
+  __ fs()->call(
+      Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAllocArrayWithAccessCheck)));
+
+  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+  DCHECK(!codegen_->IsLeafMethod());
+}
+
 void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
@@ -1119,26 +1340,42 @@
 void InstructionCodeGeneratorX86::VisitParameterValue(HParameterValue* instruction) {
 }
 
-void LocationsBuilderX86::VisitNot(HNot* instruction) {
+void LocationsBuilderX86::VisitNot(HNot* not_) {
   LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+      new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetOut(Location::SameAsFirstInput());
 }
 
-void InstructionCodeGeneratorX86::VisitNot(HNot* instruction) {
-  LocationSummary* locations = instruction->GetLocations();
+void InstructionCodeGeneratorX86::VisitNot(HNot* not_) {
+  LocationSummary* locations = not_->GetLocations();
+  DCHECK_EQ(locations->InAt(0).As<Register>(), locations->Out().As<Register>());
   Location out = locations->Out();
   DCHECK_EQ(locations->InAt(0).As<Register>(), out.As<Register>());
-  __ xorl(out.As<Register>(), Immediate(1));
+  switch (not_->InputAt(0)->GetType()) {
+    case Primitive::kPrimBoolean:
+      __ xorl(out.As<Register>(), Immediate(1));
+      break;
+
+    case Primitive::kPrimInt:
+      __ notl(out.As<Register>());
+      break;
+
+    case Primitive::kPrimLong:
+      LOG(FATAL) << "Not yet implemented type for not operation " << not_->GetResultType();
+      break;
+
+    default:
+      LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
+  }
 }
 
 void LocationsBuilderX86::VisitCompare(HCompare* compare) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
-  locations->SetInAt(1, Location::Any(), Location::kDiesAtEntry);
-  locations->SetOut(Location::RequiresRegister());
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::Any());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
 void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) {
@@ -1207,12 +1444,11 @@
       || (field_type == Primitive::kPrimByte);
   // The register allocator does not support multiple
   // inputs that die at entry with one in a specific register.
-  bool dies_at_entry = !is_object_type && !is_byte_type;
   if (is_byte_type) {
     // Ensure the value is in a byte register.
-    locations->SetInAt(1, Location::RegisterLocation(EAX), dies_at_entry);
+    locations->SetInAt(1, Location::RegisterLocation(EAX));
   } else {
-    locations->SetInAt(1, Location::RequiresRegister(), dies_at_entry);
+    locations->SetInAt(1, Location::RequiresRegister());
   }
   // Temporary registers for the write barrier.
   if (is_object_type) {
@@ -1288,8 +1524,8 @@
 void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
-  locations->SetOut(Location::RequiresRegister());
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
 void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
@@ -1356,7 +1592,7 @@
 }
 
 void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
-  SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction);
+  SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction);
   codegen_->AddSlowPath(slow_path);
 
   LocationSummary* locations = instruction->GetLocations();
@@ -1378,10 +1614,9 @@
 void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
-  locations->SetInAt(
-      1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
-  locations->SetOut(Location::RequiresRegister());
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
 void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
@@ -1494,16 +1729,13 @@
     // We need the inputs to be different than the output in case of long operation.
     // In case of a byte operation, the register allocator does not support multiple
     // inputs that die at entry with one in a specific register.
-    bool dies_at_entry = value_type != Primitive::kPrimLong && !is_byte_type;
-    locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
-    locations->SetInAt(
-        1, Location::RegisterOrConstant(instruction->InputAt(1)), dies_at_entry);
+    locations->SetInAt(0, Location::RequiresRegister());
+    locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
     if (is_byte_type) {
       // Ensure the value is in a byte register.
-      locations->SetInAt(2, Location::ByteRegisterOrConstant(
-          EAX, instruction->InputAt(2)), dies_at_entry);
+      locations->SetInAt(2, Location::ByteRegisterOrConstant(EAX, instruction->InputAt(2)));
     } else {
-      locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)), dies_at_entry);
+      locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
     }
   }
 }
@@ -1633,8 +1865,8 @@
 
 void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
-  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
-  locations->SetOut(Location::RequiresRegister());
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   instruction->SetLocations(locations);
 }
 
@@ -1658,7 +1890,7 @@
 
 void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
   LocationSummary* locations = instruction->GetLocations();
-  SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86(
+  SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86(
       instruction, locations->InAt(0), locations->InAt(1));
   codegen_->AddSlowPath(slow_path);
 
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index a1a72a2..fff91d1 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -142,10 +142,10 @@
 
   virtual void GenerateFrameEntry() OVERRIDE;
   virtual void GenerateFrameExit() OVERRIDE;
-  virtual void Bind(Label* label) OVERRIDE;
+  virtual void Bind(HBasicBlock* block) OVERRIDE;
   virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
-  virtual void SaveCoreRegister(Location stack_location, uint32_t reg_id) OVERRIDE;
-  virtual void RestoreCoreRegister(Location stack_location, uint32_t reg_id) OVERRIDE;
+  virtual size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  virtual size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
 
   virtual size_t GetWordSize() const OVERRIDE {
     return kX86WordSize;
@@ -166,6 +166,7 @@
   }
 
   virtual void SetupBlockedRegisters() const OVERRIDE;
+
   virtual Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
 
   virtual Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
@@ -173,6 +174,9 @@
   virtual void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
   virtual void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
 
+  // Blocks all register pairs made out of blocked core registers.
+  void UpdateBlockedPairRegisters() const;
+
   ParallelMoveResolverX86* GetMoveResolver() {
     return &move_resolver_;
   }
@@ -189,7 +193,17 @@
   // Emit a write barrier.
   void MarkGCCard(Register temp, Register card, Register object, Register value);
 
+  Label* GetLabelOf(HBasicBlock* block) const {
+    return block_labels_.GetRawStorage() + block->GetBlockId();
+  }
+
+  virtual void Initialize() OVERRIDE {
+    block_labels_.SetSize(GetGraph()->GetBlocks().Size());
+  }
+
  private:
+  // Labels for each block that will be compiled.
+  GrowableArray<Label> block_labels_;
   LocationsBuilderX86 location_builder_;
   InstructionCodeGeneratorX86 instruction_visitor_;
   ParallelMoveResolverX86 move_resolver_;
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 21b21f3..4a05b89 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -60,7 +60,21 @@
 
 #define __ reinterpret_cast<X86_64Assembler*>(codegen->GetAssembler())->
 
-class NullCheckSlowPathX86_64 : public SlowPathCode {
+class SlowPathCodeX86_64 : public SlowPathCode {
+ public:
+  SlowPathCodeX86_64() : entry_label_(), exit_label_() {}
+
+  Label* GetEntryLabel() { return &entry_label_; }
+  Label* GetExitLabel() { return &exit_label_; }
+
+ private:
+  Label entry_label_;
+  Label exit_label_;
+
+  DISALLOW_COPY_AND_ASSIGN(SlowPathCodeX86_64);
+};
+
+class NullCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
  public:
   explicit NullCheckSlowPathX86_64(HNullCheck* instruction) : instruction_(instruction) {}
 
@@ -76,7 +90,7 @@
   DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
 };
 
-class StackOverflowCheckSlowPathX86_64 : public SlowPathCode {
+class StackOverflowCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
  public:
   StackOverflowCheckSlowPathX86_64() {}
 
@@ -92,12 +106,13 @@
   DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathX86_64);
 };
 
-class SuspendCheckSlowPathX86_64 : public SlowPathCode {
+class SuspendCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
  public:
   explicit SuspendCheckSlowPathX86_64(HSuspendCheck* instruction, HBasicBlock* successor)
       : instruction_(instruction), successor_(successor) {}
 
   virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
     __ Bind(GetEntryLabel());
     codegen->SaveLiveRegisters(instruction_->GetLocations());
     __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pTestSuspend), true));
@@ -106,7 +121,7 @@
     if (successor_ == nullptr) {
       __ jmp(GetReturnLabel());
     } else {
-      __ jmp(codegen->GetLabelOf(successor_));
+      __ jmp(x64_codegen->GetLabelOf(successor_));
     }
   }
 
@@ -123,7 +138,7 @@
   DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
 };
 
-class BoundsCheckSlowPathX86_64 : public SlowPathCode {
+class BoundsCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
  public:
   BoundsCheckSlowPathX86_64(HBoundsCheck* instruction,
                             Location index_location,
@@ -133,7 +148,7 @@
         length_location_(length_location) {}
 
   virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
-    CodeGeneratorX86_64* x64_codegen = reinterpret_cast<CodeGeneratorX86_64*>(codegen);
+    CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
     __ Bind(GetEntryLabel());
     InvokeRuntimeCallingConvention calling_convention;
     x64_codegen->Move(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), index_location_);
@@ -176,16 +191,29 @@
   stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
 }
 
-void CodeGeneratorX86_64::SaveCoreRegister(Location stack_location, uint32_t reg_id) {
-  __ movq(Address(CpuRegister(RSP), stack_location.GetStackIndex()), CpuRegister(reg_id));
+size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
+  __ movq(Address(CpuRegister(RSP), stack_index), CpuRegister(reg_id));
+  return kX86_64WordSize;
 }
 
-void CodeGeneratorX86_64::RestoreCoreRegister(Location stack_location, uint32_t reg_id) {
-  __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_location.GetStackIndex()));
+size_t CodeGeneratorX86_64::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
+  __ movq(CpuRegister(reg_id), Address(CpuRegister(RSP), stack_index));
+  return kX86_64WordSize;
+}
+
+size_t CodeGeneratorX86_64::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
+  __ movsd(Address(CpuRegister(RSP), stack_index), XmmRegister(reg_id));
+  return kX86_64WordSize;
+}
+
+size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
+  __ movsd(XmmRegister(reg_id), Address(CpuRegister(RSP), stack_index));
+  return kX86_64WordSize;
 }
 
 CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph)
       : CodeGenerator(graph, kNumberOfCpuRegisters, kNumberOfFloatRegisters, 0),
+        block_labels_(graph->GetArena(), 0),
         location_builder_(graph, this),
         instruction_visitor_(graph, this),
         move_resolver_(graph->GetArena(), this) {}
@@ -266,7 +294,7 @@
           Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
 
   if (!skip_overflow_check && kExplicitStackOverflowCheck) {
-    SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86_64();
+    SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86_64();
     AddSlowPath(slow_path);
 
     __ gs()->cmpq(CpuRegister(RSP),
@@ -282,8 +310,8 @@
           Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
 }
 
-void CodeGeneratorX86_64::Bind(Label* label) {
-  __ Bind(label);
+void CodeGeneratorX86_64::Bind(HBasicBlock* block) {
+  __ Bind(GetLabelOf(block));
 }
 
 void InstructionCodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
@@ -375,22 +403,28 @@
 void CodeGeneratorX86_64::Move(HInstruction* instruction,
                                Location location,
                                HInstruction* move_for) {
-  if (instruction->AsIntConstant() != nullptr) {
+  if (instruction->IsIntConstant()) {
     Immediate imm(instruction->AsIntConstant()->GetValue());
     if (location.IsRegister()) {
       __ movl(location.As<CpuRegister>(), imm);
-    } else {
+    } else if (location.IsStackSlot()) {
       __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
+    } else {
+      DCHECK(location.IsConstant());
+      DCHECK_EQ(location.GetConstant(), instruction);
     }
-  } else if (instruction->AsLongConstant() != nullptr) {
+  } else if (instruction->IsLongConstant()) {
     int64_t value = instruction->AsLongConstant()->GetValue();
     if (location.IsRegister()) {
       __ movq(location.As<CpuRegister>(), Immediate(value));
-    } else {
+    } else if (location.IsDoubleStackSlot()) {
       __ movq(CpuRegister(TMP), Immediate(value));
       __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
+    } else {
+      DCHECK(location.IsConstant());
+      DCHECK_EQ(location.GetConstant(), instruction);
     }
-  } else if (instruction->AsLoadLocal() != nullptr) {
+  } else if (instruction->IsLoadLocal()) {
     switch (instruction->GetType()) {
       case Primitive::kPrimBoolean:
       case Primitive::kPrimByte:
@@ -473,46 +507,65 @@
       new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
   HInstruction* cond = if_instr->InputAt(0);
   if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
-    locations->SetInAt(0, Location::Any(), Location::kDiesAtEntry);
+    locations->SetInAt(0, Location::Any());
   }
 }
 
 void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
   HInstruction* cond = if_instr->InputAt(0);
-  bool materialized = !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
-  // Moves do not affect the eflags register, so if the condition is evaluated
-  // just before the if, we don't need to evaluate it again.
-  bool eflags_set = cond->IsCondition()
-      && cond->AsCondition()->IsBeforeWhenDisregardMoves(if_instr);
-  if (materialized) {
-    if (!eflags_set) {
-      // Materialized condition, compare against 0.
-      Location lhs = if_instr->GetLocations()->InAt(0);
-      if (lhs.IsRegister()) {
-        __ cmpl(lhs.As<CpuRegister>(), Immediate(0));
-      } else {
-        __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()), Immediate(0));
+  if (cond->IsIntConstant()) {
+    // Constant condition, statically compared against 1.
+    int32_t cond_value = cond->AsIntConstant()->GetValue();
+    if (cond_value == 1) {
+      if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
+                                     if_instr->IfTrueSuccessor())) {
+        __ jmp(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
       }
-      __ j(kNotEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
+      return;
     } else {
+      DCHECK_EQ(cond_value, 0);
+    }
+  } else {
+    bool materialized =
+        !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
+    // Moves do not affect the eflags register, so if the condition is
+    // evaluated just before the if, we don't need to evaluate it
+    // again.
+    bool eflags_set = cond->IsCondition()
+        && cond->AsCondition()->IsBeforeWhenDisregardMoves(if_instr);
+    if (materialized) {
+      if (!eflags_set) {
+        // Materialized condition, compare against 0.
+        Location lhs = if_instr->GetLocations()->InAt(0);
+        if (lhs.IsRegister()) {
+          __ cmpl(lhs.As<CpuRegister>(), Immediate(0));
+        } else {
+          __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()),
+                  Immediate(0));
+        }
+        __ j(kNotEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
+      } else {
+        __ j(X86_64Condition(cond->AsCondition()->GetCondition()),
+             codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
+      }
+    } else {
+      Location lhs = cond->GetLocations()->InAt(0);
+      Location rhs = cond->GetLocations()->InAt(1);
+      if (rhs.IsRegister()) {
+        __ cmpl(lhs.As<CpuRegister>(), rhs.As<CpuRegister>());
+      } else if (rhs.IsConstant()) {
+        __ cmpl(lhs.As<CpuRegister>(),
+                Immediate(rhs.GetConstant()->AsIntConstant()->GetValue()));
+      } else {
+        __ cmpl(lhs.As<CpuRegister>(),
+                Address(CpuRegister(RSP), rhs.GetStackIndex()));
+      }
       __ j(X86_64Condition(cond->AsCondition()->GetCondition()),
            codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
     }
-  } else {
-    Location lhs = cond->GetLocations()->InAt(0);
-    Location rhs = cond->GetLocations()->InAt(1);
-    if (rhs.IsRegister()) {
-      __ cmpl(lhs.As<CpuRegister>(), rhs.As<CpuRegister>());
-    } else if (rhs.IsConstant()) {
-      __ cmpl(lhs.As<CpuRegister>(),
-              Immediate(rhs.GetConstant()->AsIntConstant()->GetValue()));
-    } else {
-      __ cmpl(lhs.As<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
-    }
-    __ j(X86_64Condition(cond->AsCondition()->GetCondition()),
-         codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
   }
-  if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
+  if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
+                                 if_instr->IfFalseSuccessor())) {
     __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
   }
 }
@@ -563,8 +616,8 @@
 void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
-  locations->SetInAt(1, Location::Any(), Location::kDiesAtEntry);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::Any());
   if (comp->NeedsMaterialization()) {
     locations->SetOut(Location::RequiresRegister());
   }
@@ -641,9 +694,9 @@
 void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
-  locations->SetInAt(1, Location::RequiresRegister(), Location::kDiesAtEntry);
-  locations->SetOut(Location::RequiresRegister());
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
 void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
@@ -679,6 +732,7 @@
 }
 
 void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
+  // Will be generated at use site.
 }
 
 void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
@@ -688,6 +742,27 @@
 }
 
 void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
+  // Will be generated at use site.
+}
+
+void LocationsBuilderX86_64::VisitFloatConstant(HFloatConstant* constant) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
+  locations->SetOut(Location::ConstantLocation(constant));
+}
+
+void InstructionCodeGeneratorX86_64::VisitFloatConstant(HFloatConstant* constant) {
+  // Will be generated at use site.
+}
+
+void LocationsBuilderX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
+  locations->SetOut(Location::ConstantLocation(constant));
+}
+
+void InstructionCodeGeneratorX86_64::VisitDoubleConstant(HDoubleConstant* constant) {
+  // Will be generated at use site.
 }
 
 void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
@@ -896,6 +971,47 @@
   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
 }
 
+void LocationsBuilderX86_64::VisitNeg(HNeg* neg) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
+  switch (neg->GetResultType()) {
+    case Primitive::kPrimInt:
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetOut(Location::SameAsFirstInput());
+      break;
+
+    case Primitive::kPrimLong:
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
+  }
+}
+
+void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
+  LocationSummary* locations = neg->GetLocations();
+  Location out = locations->Out();
+  Location in = locations->InAt(0);
+  switch (neg->GetResultType()) {
+    case Primitive::kPrimInt:
+      DCHECK(in.IsRegister());
+      __ negl(out.As<CpuRegister>());
+      break;
+
+    case Primitive::kPrimLong:
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
+  }
+}
+
 void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
@@ -917,7 +1033,7 @@
     case Primitive::kPrimDouble:
     case Primitive::kPrimFloat: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
-      locations->SetInAt(1, Location::Any());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
       locations->SetOut(Location::SameAsFirstInput());
       break;
     }
@@ -931,19 +1047,17 @@
   LocationSummary* locations = add->GetLocations();
   Location first = locations->InAt(0);
   Location second = locations->InAt(1);
-
   DCHECK(first.Equals(locations->Out()));
+
   switch (add->GetResultType()) {
     case Primitive::kPrimInt: {
       if (second.IsRegister()) {
         __ addl(first.As<CpuRegister>(), second.As<CpuRegister>());
       } else if (second.IsConstant()) {
-        HConstant* instruction = second.GetConstant();
-        Immediate imm(instruction->AsIntConstant()->GetValue());
+        Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
         __ addl(first.As<CpuRegister>(), imm);
       } else {
-        __ addl(first.As<CpuRegister>(),
-                Address(CpuRegister(RSP), second.GetStackIndex()));
+        __ addl(first.As<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
       }
       break;
     }
@@ -954,21 +1068,12 @@
     }
 
     case Primitive::kPrimFloat: {
-      if (second.IsFpuRegister()) {
-        __ addss(first.As<XmmRegister>(), second.As<XmmRegister>());
-      } else {
-        __ addss(first.As<XmmRegister>(),
-                 Address(CpuRegister(RSP), second.GetStackIndex()));
-      }
+      __ addss(first.As<XmmRegister>(), second.As<XmmRegister>());
       break;
     }
 
     case Primitive::kPrimDouble: {
-      if (second.IsFpuRegister()) {
-        __ addsd(first.As<XmmRegister>(), second.As<XmmRegister>());
-      } else {
-        __ addsd(first.As<XmmRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
-      }
+      __ addsd(first.As<XmmRegister>(), second.As<XmmRegister>());
       break;
     }
 
@@ -993,53 +1098,119 @@
       locations->SetOut(Location::SameAsFirstInput());
       break;
     }
-
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetOut(Location::SameAsFirstInput());
       break;
-
+    }
     default:
-      LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
+      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
   }
 }
 
 void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
   LocationSummary* locations = sub->GetLocations();
-  DCHECK_EQ(locations->InAt(0).As<CpuRegister>().AsRegister(),
-            locations->Out().As<CpuRegister>().AsRegister());
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
+  DCHECK(first.Equals(locations->Out()));
   switch (sub->GetResultType()) {
     case Primitive::kPrimInt: {
-      if (locations->InAt(1).IsRegister()) {
-        __ subl(locations->InAt(0).As<CpuRegister>(),
-                locations->InAt(1).As<CpuRegister>());
-      } else if (locations->InAt(1).IsConstant()) {
-        HConstant* instruction = locations->InAt(1).GetConstant();
-        Immediate imm(instruction->AsIntConstant()->GetValue());
-        __ subl(locations->InAt(0).As<CpuRegister>(), imm);
+      if (second.IsRegister()) {
+        __ subl(first.As<CpuRegister>(), second.As<CpuRegister>());
+      } else if (second.IsConstant()) {
+        Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
+        __ subl(first.As<CpuRegister>(), imm);
       } else {
-        __ subl(locations->InAt(0).As<CpuRegister>(),
-                Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
+        __ subl(first.As<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
       }
       break;
     }
     case Primitive::kPrimLong: {
-      __ subq(locations->InAt(0).As<CpuRegister>(),
-              locations->InAt(1).As<CpuRegister>());
+      __ subq(first.As<CpuRegister>(), second.As<CpuRegister>());
       break;
     }
 
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
+    case Primitive::kPrimFloat: {
+      __ subss(first.As<XmmRegister>(), second.As<XmmRegister>());
       break;
+    }
+
+    case Primitive::kPrimDouble: {
+      __ subsd(first.As<XmmRegister>(), second.As<XmmRegister>());
+      break;
+    }
 
     default:
-      LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
+      LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
+  }
+}
+
+void LocationsBuilderX86_64::VisitMul(HMul* mul) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
+  switch (mul->GetResultType()) {
+    case Primitive::kPrimInt: {
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::Any());
+      locations->SetOut(Location::SameAsFirstInput());
+      break;
+    }
+    case Primitive::kPrimLong: {
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::RequiresRegister());
+      locations->SetOut(Location::SameAsFirstInput());
+      break;
+    }
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetOut(Location::SameAsFirstInput());
+      break;
+    }
+
+    default:
+      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
+  }
+}
+
+void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) {
+  LocationSummary* locations = mul->GetLocations();
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
+  DCHECK(first.Equals(locations->Out()));
+  switch (mul->GetResultType()) {
+    case Primitive::kPrimInt: {
+      if (second.IsRegister()) {
+        __ imull(first.As<CpuRegister>(), second.As<CpuRegister>());
+      } else if (second.IsConstant()) {
+        Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
+        __ imull(first.As<CpuRegister>(), imm);
+      } else {
+        DCHECK(second.IsStackSlot());
+        __ imull(first.As<CpuRegister>(), Address(CpuRegister(RSP), second.GetStackIndex()));
+      }
+      break;
+    }
+    case Primitive::kPrimLong: {
+      __ imulq(first.As<CpuRegister>(), second.As<CpuRegister>());
+      break;
+    }
+
+    case Primitive::kPrimFloat: {
+      __ mulss(first.As<XmmRegister>(), second.As<XmmRegister>());
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      __ mulsd(first.As<XmmRegister>(), second.As<XmmRegister>());
+      break;
+    }
+
+    default:
+      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
   }
 }
 
@@ -1064,6 +1235,28 @@
   codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
 }
 
+void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+  InvokeRuntimeCallingConvention calling_convention;
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+  locations->SetOut(Location::RegisterLocation(RAX));
+  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
+}
+
+void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
+  InvokeRuntimeCallingConvention calling_convention;
+  LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
+  __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
+
+  __ gs()->call(Address::Absolute(
+      QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocArrayWithAccessCheck), true));
+
+  DCHECK(!codegen_->IsLeafMethod());
+  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+}
+
 void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
@@ -1080,18 +1273,34 @@
   // Nothing to do, the parameter is already at its location.
 }
 
-void LocationsBuilderX86_64::VisitNot(HNot* instruction) {
+void LocationsBuilderX86_64::VisitNot(HNot* not_) {
   LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+      new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetOut(Location::SameAsFirstInput());
 }
 
-void InstructionCodeGeneratorX86_64::VisitNot(HNot* instruction) {
-  LocationSummary* locations = instruction->GetLocations();
+void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
+  LocationSummary* locations = not_->GetLocations();
   DCHECK_EQ(locations->InAt(0).As<CpuRegister>().AsRegister(),
             locations->Out().As<CpuRegister>().AsRegister());
-  __ xorq(locations->Out().As<CpuRegister>(), Immediate(1));
+  Location out = locations->Out();
+  switch (not_->InputAt(0)->GetType()) {
+    case Primitive::kPrimBoolean:
+      __ xorq(out.As<CpuRegister>(), Immediate(1));
+      break;
+
+    case Primitive::kPrimInt:
+      __ notl(out.As<CpuRegister>());
+      break;
+
+    case Primitive::kPrimLong:
+      LOG(FATAL) << "Not yet implemented type for not operation " << not_->GetResultType();
+      break;
+
+    default:
+      LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
+  }
 }
 
 void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
@@ -1112,9 +1321,8 @@
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   Primitive::Type field_type = instruction->GetFieldType();
   bool is_object_type = field_type == Primitive::kPrimNot;
-  bool dies_at_entry = !is_object_type;
-  locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry);
-  locations->SetInAt(1, Location::RequiresRegister(), dies_at_entry);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
   if (is_object_type) {
     // Temporary registers for the write barrier.
     locations->AddTemp(Location::RequiresRegister());
@@ -1171,8 +1379,8 @@
 void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
-  locations->SetOut(Location::RequiresRegister());
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
 void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
@@ -1233,7 +1441,7 @@
 }
 
 void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
-  SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
+  SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction);
   codegen_->AddSlowPath(slow_path);
 
   LocationSummary* locations = instruction->GetLocations();
@@ -1255,10 +1463,10 @@
 void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
+  locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(
-      1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
-  locations->SetOut(Location::RequiresRegister());
+      1, Location::RegisterOrConstant(instruction->InputAt(1)));
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
 void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
@@ -1341,10 +1549,30 @@
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
-      LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
-      UNREACHABLE();
+    case Primitive::kPrimFloat: {
+      uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
+      XmmRegister out = locations->Out().As<XmmRegister>();
+      if (index.IsConstant()) {
+        __ movss(out, Address(obj,
+            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
+      } else {
+        __ movss(out, Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset));
+      }
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
+      XmmRegister out = locations->Out().As<XmmRegister>();
+      if (index.IsConstant()) {
+        __ movsd(out, Address(obj,
+            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
+      } else {
+        __ movsd(out, Address(obj, index.As<CpuRegister>(), TIMES_8, data_offset));
+      }
+      break;
+    }
+
     case Primitive::kPrimVoid:
       LOG(FATAL) << "Unreachable type " << instruction->GetType();
       UNREACHABLE();
@@ -1362,14 +1590,16 @@
     locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
     locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
   } else {
-    locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
+    locations->SetInAt(0, Location::RequiresRegister());
     locations->SetInAt(
-        1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry);
-    locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry);
+        1, Location::RegisterOrConstant(instruction->InputAt(1)));
+    locations->SetInAt(2, Location::RequiresRegister());
     if (value_type == Primitive::kPrimLong) {
-      locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry);
+      locations->SetInAt(2, Location::RequiresRegister());
+    } else if (value_type == Primitive::kPrimFloat || value_type == Primitive::kPrimDouble) {
+      locations->SetInAt(2, Location::RequiresFpuRegister());
     } else {
-      locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)), Location::kDiesAtEntry);
+      locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
     }
   }
 }
@@ -1440,6 +1670,7 @@
           __ movl(Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset),
                   value.As<CpuRegister>());
         } else {
+          DCHECK(value.IsConstant()) << value;
           __ movl(Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset),
                   Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
         }
@@ -1468,10 +1699,34 @@
       break;
     }
 
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
-      LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
-      UNREACHABLE();
+    case Primitive::kPrimFloat: {
+      uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
+      if (index.IsConstant()) {
+        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+        DCHECK(value.IsFpuRegister());
+        __ movss(Address(obj, offset), value.As<XmmRegister>());
+      } else {
+        DCHECK(value.IsFpuRegister());
+        __ movss(Address(obj, index.As<CpuRegister>(), TIMES_4, data_offset),
+                value.As<XmmRegister>());
+      }
+      break;
+    }
+
+    case Primitive::kPrimDouble: {
+      uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
+      if (index.IsConstant()) {
+        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
+        DCHECK(value.IsFpuRegister());
+        __ movsd(Address(obj, offset), value.As<XmmRegister>());
+      } else {
+        DCHECK(value.IsFpuRegister());
+        __ movsd(Address(obj, index.As<CpuRegister>(), TIMES_8, data_offset),
+                value.As<XmmRegister>());
+      }
+      break;
+    }
+
     case Primitive::kPrimVoid:
       LOG(FATAL) << "Unreachable type " << instruction->GetType();
       UNREACHABLE();
@@ -1481,8 +1736,8 @@
 void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry);
-  locations->SetOut(Location::RequiresRegister());
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
 void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
@@ -1505,7 +1760,7 @@
 
 void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
   LocationSummary* locations = instruction->GetLocations();
-  SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(
+  SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(
       instruction, locations->InAt(0), locations->InAt(1));
   codegen_->AddSlowPath(slow_path);
 
@@ -1605,6 +1860,9 @@
     if (destination.IsRegister()) {
       __ movl(destination.As<CpuRegister>(),
               Address(CpuRegister(RSP), source.GetStackIndex()));
+    } else if (destination.IsFpuRegister()) {
+      __ movss(destination.As<XmmRegister>(),
+              Address(CpuRegister(RSP), source.GetStackIndex()));
     } else {
       DCHECK(destination.IsStackSlot());
       __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
@@ -1614,8 +1872,10 @@
     if (destination.IsRegister()) {
       __ movq(destination.As<CpuRegister>(),
               Address(CpuRegister(RSP), source.GetStackIndex()));
+    } else if (destination.IsFpuRegister()) {
+      __ movsd(destination.As<XmmRegister>(), Address(CpuRegister(RSP), source.GetStackIndex()));
     } else {
-      DCHECK(destination.IsDoubleStackSlot());
+      DCHECK(destination.IsDoubleStackSlot()) << destination;
       __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
       __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
     }
@@ -1626,6 +1886,7 @@
       if (destination.IsRegister()) {
         __ movl(destination.As<CpuRegister>(), imm);
       } else {
+        DCHECK(destination.IsStackSlot()) << destination;
         __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
       }
     } else if (constant->IsLongConstant()) {
@@ -1633,14 +1894,42 @@
       if (destination.IsRegister()) {
         __ movq(destination.As<CpuRegister>(), Immediate(value));
       } else {
+        DCHECK(destination.IsDoubleStackSlot()) << destination;
         __ movq(CpuRegister(TMP), Immediate(value));
         __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
       }
+    } else if (constant->IsFloatConstant()) {
+      Immediate imm(bit_cast<float, int32_t>(constant->AsFloatConstant()->GetValue()));
+      if (destination.IsFpuRegister()) {
+        __ movl(CpuRegister(TMP), imm);
+        __ movd(destination.As<XmmRegister>(), CpuRegister(TMP));
+      } else {
+        DCHECK(destination.IsStackSlot()) << destination;
+        __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
+      }
     } else {
-      LOG(FATAL) << "Unimplemented constant type";
+      DCHECK(constant->IsDoubleConstant()) << constant->DebugName();
+      Immediate imm(bit_cast<double, int64_t>(constant->AsDoubleConstant()->GetValue()));
+      if (destination.IsFpuRegister()) {
+        __ movq(CpuRegister(TMP), imm);
+        __ movd(destination.As<XmmRegister>(), CpuRegister(TMP));
+      } else {
+        DCHECK(destination.IsDoubleStackSlot()) << destination;
+        __ movq(CpuRegister(TMP), imm);
+        __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
+      }
     }
-  } else {
-    LOG(FATAL) << "Unimplemented";
+  } else if (source.IsFpuRegister()) {
+    if (destination.IsFpuRegister()) {
+      __ movaps(destination.As<XmmRegister>(), source.As<XmmRegister>());
+    } else if (destination.IsStackSlot()) {
+      __ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
+               source.As<XmmRegister>());
+    } else {
+      DCHECK(destination.IsDoubleStackSlot());
+      __ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
+               source.As<XmmRegister>());
+    }
   }
 }
 
@@ -1682,6 +1971,18 @@
           CpuRegister(ensure_scratch.GetRegister()));
 }
 
+void ParallelMoveResolverX86_64::Exchange32(XmmRegister reg, int mem) {
+  __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
+  __ movss(Address(CpuRegister(RSP), mem), reg);
+  __ movd(reg, CpuRegister(TMP));
+}
+
+void ParallelMoveResolverX86_64::Exchange64(XmmRegister reg, int mem) {
+  __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
+  __ movsd(Address(CpuRegister(RSP), mem), reg);
+  __ movd(reg, CpuRegister(TMP));
+}
+
 void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
   MoveOperands* move = moves_.Get(index);
   Location source = move->GetSource();
@@ -1701,8 +2002,20 @@
     Exchange64(destination.As<CpuRegister>(), source.GetStackIndex());
   } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
     Exchange64(destination.GetStackIndex(), source.GetStackIndex());
+  } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
+    __ movd(CpuRegister(TMP), source.As<XmmRegister>());
+    __ movaps(source.As<XmmRegister>(), destination.As<XmmRegister>());
+    __ movd(destination.As<XmmRegister>(), CpuRegister(TMP));
+  } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
+    Exchange32(source.As<XmmRegister>(), destination.GetStackIndex());
+  } else if (source.IsStackSlot() && destination.IsFpuRegister()) {
+    Exchange32(destination.As<XmmRegister>(), source.GetStackIndex());
+  } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
+    Exchange64(source.As<XmmRegister>(), destination.GetStackIndex());
+  } else if (source.IsDoubleStackSlot() && destination.IsFpuRegister()) {
+    Exchange64(destination.As<XmmRegister>(), source.GetStackIndex());
   } else {
-    LOG(FATAL) << "Unimplemented";
+    LOG(FATAL) << "Unimplemented swap between " << source << " and " << destination;
   }
 }
 
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 288f3f6..e04a8d8 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -80,8 +80,10 @@
 
  private:
   void Exchange32(CpuRegister reg, int mem);
+  void Exchange32(XmmRegister reg, int mem);
   void Exchange32(int mem1, int mem2);
   void Exchange64(CpuRegister reg, int mem);
+  void Exchange64(XmmRegister reg, int mem);
   void Exchange64(int mem1, int mem2);
 
   CodeGeneratorX86_64* const codegen_;
@@ -144,10 +146,12 @@
 
   virtual void GenerateFrameEntry() OVERRIDE;
   virtual void GenerateFrameExit() OVERRIDE;
-  virtual void Bind(Label* label) OVERRIDE;
+  virtual void Bind(HBasicBlock* block) OVERRIDE;
   virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
-  virtual void SaveCoreRegister(Location stack_location, uint32_t reg_id) OVERRIDE;
-  virtual void RestoreCoreRegister(Location stack_location, uint32_t reg_id) OVERRIDE;
+  virtual size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  virtual size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  virtual size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  virtual size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
 
   virtual size_t GetWordSize() const OVERRIDE {
     return kX86_64WordSize;
@@ -188,7 +192,17 @@
   // Helper method to move a value between two locations.
   void Move(Location destination, Location source);
 
+  Label* GetLabelOf(HBasicBlock* block) const {
+    return block_labels_.GetRawStorage() + block->GetBlockId();
+  }
+
+  virtual void Initialize() OVERRIDE {
+    block_labels_.SetSize(GetGraph()->GetBlocks().Size());
+  }
+
  private:
+  // Labels for each block that will be compiled.
+  GrowableArray<Label> block_labels_;
   LocationsBuilderX86_64 location_builder_;
   InstructionCodeGeneratorX86_64 instruction_visitor_;
   ParallelMoveResolverX86_64 move_resolver_;
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index 3037f1c..03951e2 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -16,8 +16,10 @@
 
 #include <functional>
 
+#include "base/macros.h"
 #include "builder.h"
 #include "code_generator_arm.h"
+#include "code_generator_arm64.h"
 #include "code_generator_x86.h"
 #include "code_generator_x86_64.h"
 #include "common_compiler_test.h"
@@ -93,6 +95,12 @@
   if (kRuntimeISA == kX86_64) {
     Run(allocator, codegenX86_64, has_result, expected);
   }
+
+  arm64::CodeGeneratorARM64 codegenARM64(graph);
+  codegenARM64.CompileBaseline(&allocator, true);
+  if (kRuntimeISA == kArm64) {
+    Run(allocator, codegenARM64, has_result, expected);
+  }
 }
 
 static void RunCodeOptimized(CodeGenerator* codegen,
@@ -134,9 +142,9 @@
   HGraphBuilder builder(&arena);
   const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
   HGraph* graph = builder.BuildGraph(*item);
+  ASSERT_NE(graph, nullptr);
   // Remove suspend checks, they cannot be executed in this context.
   RemoveSuspendChecks(graph);
-  ASSERT_NE(graph, nullptr);
   RunCodeBaseline(graph, has_result, expected);
 }
 
@@ -260,6 +268,31 @@
   TestCode(data, true, 0);
 }
 
+// Exercise bit-wise (one's complement) not-int instruction.
+#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
+TEST(CodegenTest, TEST_NAME) {                          \
+  const int32_t input = INPUT;                          \
+  const uint16_t input_lo = input & 0x0000FFFF;         \
+  const uint16_t input_hi = input >> 16;                \
+  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(      \
+      Instruction::CONST | 0 << 8, input_lo, input_hi,  \
+      Instruction::NOT_INT | 1 << 8 | 0 << 12 ,         \
+      Instruction::RETURN | 1 << 8);                    \
+                                                        \
+  TestCode(data, true, EXPECTED_OUTPUT);                \
+}
+
+NOT_INT_TEST(ReturnNotIntMinus2, -2, 1)
+NOT_INT_TEST(ReturnNotIntMinus1, -1, 0)
+NOT_INT_TEST(ReturnNotInt0, 0, -1)
+NOT_INT_TEST(ReturnNotInt1, 1, -2)
+NOT_INT_TEST(ReturnNotIntINT_MIN, -2147483648, 2147483647)  // (2^31) - 1
+NOT_INT_TEST(ReturnNotIntINT_MINPlus1, -2147483647, 2147483646)  // (2^31) - 2
+NOT_INT_TEST(ReturnNotIntINT_MAXMinus1, 2147483646, -2147483647)  // -(2^31) - 1
+NOT_INT_TEST(ReturnNotIntINT_MAX, 2147483647, -2147483648)  // -(2^31)
+
+#undef NOT_INT_TEST
+
 TEST(CodegenTest, ReturnAdd1) {
   const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 3 << 12 | 0,
@@ -349,4 +382,173 @@
   RunCodeOptimized(graph, hook_before_codegen, true, 0);
 }
 
+#define MUL_TEST(TYPE, TEST_NAME)                     \
+  TEST(CodegenTest, Return ## TEST_NAME) {            \
+    const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(  \
+      Instruction::CONST_4 | 3 << 12 | 0,             \
+      Instruction::CONST_4 | 4 << 12 | 1 << 8,        \
+      Instruction::MUL_ ## TYPE, 1 << 8 | 0,          \
+      Instruction::RETURN);                           \
+                                                      \
+    TestCode(data, true, 12);                         \
+  }                                                   \
+                                                      \
+  TEST(CodegenTest, Return ## TEST_NAME ## 2addr) {   \
+    const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(  \
+      Instruction::CONST_4 | 3 << 12 | 0,             \
+      Instruction::CONST_4 | 4 << 12 | 1 << 8,        \
+      Instruction::MUL_ ## TYPE ## _2ADDR | 1 << 12,  \
+      Instruction::RETURN);                           \
+                                                      \
+    TestCode(data, true, 12);                         \
+  }
+
+#if !defined(__aarch64__)
+MUL_TEST(INT, MulInt);
+MUL_TEST(LONG, MulLong);
+#endif
+
+#if defined(__aarch64__)
+TEST(CodegenTest, DISABLED_ReturnMulIntLit8) {
+#else
+TEST(CodegenTest, ReturnMulIntLit8) {
+#endif
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 4 << 12 | 0 << 8,
+    Instruction::MUL_INT_LIT8, 3 << 8 | 0,
+    Instruction::RETURN);
+
+  TestCode(data, true, 12);
+}
+
+#if defined(__aarch64__)
+TEST(CodegenTest, DISABLED_ReturnMulIntLit16) {
+#else
+TEST(CodegenTest, ReturnMulIntLit16) {
+#endif
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 4 << 12 | 0 << 8,
+    Instruction::MUL_INT_LIT16, 3,
+    Instruction::RETURN);
+
+  TestCode(data, true, 12);
+}
+
+TEST(CodegenTest, MaterializedCondition1) {
+  // Check that condition are materialized correctly. A materialized condition
+  // should yield `1` if it evaluated to true, and `0` otherwise.
+  // We force the materialization of comparisons for different combinations of
+  // inputs and check the results.
+
+  int lhs[] = {1, 2, -1, 2, 0xabc};
+  int rhs[] = {2, 1, 2, -1, 0xabc};
+
+  for (size_t i = 0; i < arraysize(lhs); i++) {
+    ArenaPool pool;
+    ArenaAllocator allocator(&pool);
+    HGraph* graph = new (&allocator) HGraph(&allocator);
+
+    HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
+    graph->AddBlock(entry_block);
+    graph->SetEntryBlock(entry_block);
+    entry_block->AddInstruction(new (&allocator) HGoto());
+    HBasicBlock* code_block = new (&allocator) HBasicBlock(graph);
+    graph->AddBlock(code_block);
+    HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
+    graph->AddBlock(exit_block);
+    exit_block->AddInstruction(new (&allocator) HExit());
+
+    entry_block->AddSuccessor(code_block);
+    code_block->AddSuccessor(exit_block);
+    graph->SetExitBlock(exit_block);
+
+    HIntConstant cst_lhs(lhs[i]);
+    code_block->AddInstruction(&cst_lhs);
+    HIntConstant cst_rhs(rhs[i]);
+    code_block->AddInstruction(&cst_rhs);
+    HLessThan cmp_lt(&cst_lhs, &cst_rhs);
+    code_block->AddInstruction(&cmp_lt);
+    HReturn ret(&cmp_lt);
+    code_block->AddInstruction(&ret);
+
+    auto hook_before_codegen = [](HGraph* graph) {
+      HBasicBlock* block = graph->GetEntryBlock()->GetSuccessors().Get(0);
+      HParallelMove* move = new (graph->GetArena()) HParallelMove(graph->GetArena());
+      block->InsertInstructionBefore(move, block->GetLastInstruction());
+    };
+
+    RunCodeOptimized(graph, hook_before_codegen, true, lhs[i] < rhs[i]);
+  }
+}
+
+TEST(CodegenTest, MaterializedCondition2) {
+  // Check that HIf correctly interprets a materialized condition.
+  // We force the materialization of comparisons for different combinations of
+  // inputs. An HIf takes the materialized combination as input and returns a
+  // value that we verify.
+
+  int lhs[] = {1, 2, -1, 2, 0xabc};
+  int rhs[] = {2, 1, 2, -1, 0xabc};
+
+
+  for (size_t i = 0; i < arraysize(lhs); i++) {
+    ArenaPool pool;
+    ArenaAllocator allocator(&pool);
+    HGraph* graph = new (&allocator) HGraph(&allocator);
+
+    HBasicBlock* entry_block = new (&allocator) HBasicBlock(graph);
+    graph->AddBlock(entry_block);
+    graph->SetEntryBlock(entry_block);
+    entry_block->AddInstruction(new (&allocator) HGoto());
+
+    HBasicBlock* if_block = new (&allocator) HBasicBlock(graph);
+    graph->AddBlock(if_block);
+    HBasicBlock* if_true_block = new (&allocator) HBasicBlock(graph);
+    graph->AddBlock(if_true_block);
+    HBasicBlock* if_false_block = new (&allocator) HBasicBlock(graph);
+    graph->AddBlock(if_false_block);
+    HBasicBlock* exit_block = new (&allocator) HBasicBlock(graph);
+    graph->AddBlock(exit_block);
+    exit_block->AddInstruction(new (&allocator) HExit());
+
+    graph->SetEntryBlock(entry_block);
+    entry_block->AddSuccessor(if_block);
+    if_block->AddSuccessor(if_true_block);
+    if_block->AddSuccessor(if_false_block);
+    if_true_block->AddSuccessor(exit_block);
+    if_false_block->AddSuccessor(exit_block);
+    graph->SetExitBlock(exit_block);
+
+    HIntConstant cst_lhs(lhs[i]);
+    if_block->AddInstruction(&cst_lhs);
+    HIntConstant cst_rhs(rhs[i]);
+    if_block->AddInstruction(&cst_rhs);
+    HLessThan cmp_lt(&cst_lhs, &cst_rhs);
+    if_block->AddInstruction(&cmp_lt);
+    // We insert a temporary to separate the HIf from the HLessThan and force
+    // the materialization of the condition.
+    HTemporary force_materialization(0);
+    if_block->AddInstruction(&force_materialization);
+    HIf if_lt(&cmp_lt);
+    if_block->AddInstruction(&if_lt);
+
+    HIntConstant cst_lt(1);
+    if_true_block->AddInstruction(&cst_lt);
+    HReturn ret_lt(&cst_lt);
+    if_true_block->AddInstruction(&ret_lt);
+    HIntConstant cst_ge(0);
+    if_false_block->AddInstruction(&cst_ge);
+    HReturn ret_ge(&cst_ge);
+    if_false_block->AddInstruction(&ret_ge);
+
+    auto hook_before_codegen = [](HGraph* graph) {
+      HBasicBlock* block = graph->GetEntryBlock()->GetSuccessors().Get(0);
+      HParallelMove* move = new (graph->GetArena()) HParallelMove(graph->GetArena());
+      block->InsertInstructionBefore(move, block->GetLastInstruction());
+    };
+
+    RunCodeOptimized(graph, hook_before_codegen, true, lhs[i] < rhs[i]);
+  }
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/constant_propagation.cc b/compiler/optimizing/constant_folding.cc
similarity index 71%
rename from compiler/optimizing/constant_propagation.cc
rename to compiler/optimizing/constant_folding.cc
index d675164..10a7e46 100644
--- a/compiler/optimizing/constant_propagation.cc
+++ b/compiler/optimizing/constant_folding.cc
@@ -14,11 +14,11 @@
  * limitations under the License.
  */
 
-#include "constant_propagation.h"
+#include "constant_folding.h"
 
 namespace art {
 
-void ConstantPropagation::Run() {
+void HConstantFolding::Run() {
   // Process basic blocks in reverse post-order in the dominator tree,
   // so that an instruction turned into a constant, used as input of
   // another instruction, may possibly be used to turn that second
@@ -31,11 +31,19 @@
     for (HInstructionIterator it(block->GetInstructions());
          !it.Done(); it.Advance()) {
       HInstruction* inst = it.Current();
-      // Constant folding: replace `c <- a op b' with a compile-time
-      // evaluation of `a op b' if `a' and `b' are constant.
       if (inst->IsBinaryOperation()) {
+        // Constant folding: replace `op(a, b)' with a constant at
+        // compile time if `a' and `b' are both constants.
         HConstant* constant =
-          inst->AsBinaryOperation()->TryStaticEvaluation(graph_->GetArena());
+            inst->AsBinaryOperation()->TryStaticEvaluation();
+        if (constant != nullptr) {
+          inst->GetBlock()->ReplaceAndRemoveInstructionWith(inst, constant);
+        }
+      } else if (inst->IsUnaryOperation()) {
+        // Constant folding: replace `op(a)' with a constant at compile
+        // time if `a' is a constant.
+        HConstant* constant =
+            inst->AsUnaryOperation()->TryStaticEvaluation();
         if (constant != nullptr) {
           inst->GetBlock()->ReplaceAndRemoveInstructionWith(inst, constant);
         }
diff --git a/compiler/optimizing/constant_folding.h b/compiler/optimizing/constant_folding.h
new file mode 100644
index 0000000..d2acfa6
--- /dev/null
+++ b/compiler/optimizing/constant_folding.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 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_COMPILER_OPTIMIZING_CONSTANT_FOLDING_H_
+#define ART_COMPILER_OPTIMIZING_CONSTANT_FOLDING_H_
+
+#include "nodes.h"
+#include "optimization.h"
+
+namespace art {
+
+/**
+ * Optimization pass performing a simple constant-expression
+ * evaluation on the SSA form.
+ *
+ * This class is named art::HConstantFolding to avoid name
+ * clashes with the art::ConstantPropagation class defined in
+ * compiler/dex/post_opt_passes.h.
+ */
+class HConstantFolding : public HOptimization {
+ public:
+  HConstantFolding(HGraph* graph, const HGraphVisualizer& visualizer)
+      : HOptimization(graph, true, kConstantFoldingPassName, visualizer) {}
+
+  virtual void Run() OVERRIDE;
+
+  static constexpr const char* kConstantFoldingPassName = "constant_folding";
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HConstantFolding);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_OPTIMIZING_CONSTANT_FOLDING_H_
diff --git a/compiler/optimizing/constant_propagation_test.cc b/compiler/optimizing/constant_folding_test.cc
similarity index 77%
rename from compiler/optimizing/constant_propagation_test.cc
rename to compiler/optimizing/constant_folding_test.cc
index 342777a..09bf2c8 100644
--- a/compiler/optimizing/constant_propagation_test.cc
+++ b/compiler/optimizing/constant_folding_test.cc
@@ -16,11 +16,12 @@
 
 #include <functional>
 
-#include "constant_propagation.h"
+#include "code_generator_x86.h"
+#include "constant_folding.h"
 #include "dead_code_elimination.h"
-#include "pretty_printer.h"
 #include "graph_checker.h"
 #include "optimizing_unit_test.h"
+#include "pretty_printer.h"
 
 #include "gtest/gtest.h"
 
@@ -28,9 +29,9 @@
 
 static void TestCode(const uint16_t* data,
                      const std::string& expected_before,
-                     const std::string& expected_after_cp,
+                     const std::string& expected_after_cf,
                      const std::string& expected_after_dce,
-                     std::function<void(HGraph*)> check_after_cp,
+                     std::function<void(HGraph*)> check_after_cf,
                      Primitive::Type return_type = Primitive::kPrimInt) {
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
@@ -45,29 +46,87 @@
   std::string actual_before = printer_before.str();
   ASSERT_EQ(expected_before, actual_before);
 
-  ConstantPropagation(graph).Run();
+  x86::CodeGeneratorX86 codegen(graph);
+  HGraphVisualizer visualizer(nullptr, graph, codegen, "");
+  HConstantFolding(graph, visualizer).Run();
+  SSAChecker ssa_checker(&allocator, graph);
+  ssa_checker.Run();
+  ASSERT_TRUE(ssa_checker.IsValid());
 
-  StringPrettyPrinter printer_after_cp(graph);
-  printer_after_cp.VisitInsertionOrder();
-  std::string actual_after_cp = printer_after_cp.str();
-  ASSERT_EQ(expected_after_cp, actual_after_cp);
+  StringPrettyPrinter printer_after_cf(graph);
+  printer_after_cf.VisitInsertionOrder();
+  std::string actual_after_cf = printer_after_cf.str();
+  ASSERT_EQ(expected_after_cf, actual_after_cf);
 
-  check_after_cp(graph);
+  check_after_cf(graph);
 
-  DeadCodeElimination(graph).Run();
+  HDeadCodeElimination(graph, visualizer).Run();
+  ssa_checker.Run();
+  ASSERT_TRUE(ssa_checker.IsValid());
 
   StringPrettyPrinter printer_after_dce(graph);
   printer_after_dce.VisitInsertionOrder();
   std::string actual_after_dce = printer_after_dce.str();
   ASSERT_EQ(expected_after_dce, actual_after_dce);
-
-  SSAChecker ssa_checker(&allocator, graph);
-  ssa_checker.VisitInsertionOrder();
-  ASSERT_TRUE(ssa_checker.IsValid());
 }
 
 
 /**
+ * Tiny three-register program exercising int constant folding on negation.
+ *
+ *                              16-bit
+ *                              offset
+ *                              ------
+ *     v0 <- 1                  0.      const/4 v0, #+1
+ *     v1 <- -v0                1.      neg-int v0, v1
+ *     return v1                2.      return v1
+ */
+TEST(ConstantFolding, IntConstantFoldingNegation) {
+  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+    Instruction::CONST_4 | 0 << 8 | 1 << 12,
+    Instruction::NEG_INT | 1 << 8 | 0 << 12,
+    Instruction::RETURN | 1 << 8);
+
+  std::string expected_before =
+      "BasicBlock 0, succ: 1\n"
+      "  2: IntConstant [5]\n"
+      "  10: SuspendCheck\n"
+      "  11: Goto 1\n"
+      "BasicBlock 1, pred: 0, succ: 2\n"
+      "  5: Neg(2) [8]\n"
+      "  8: Return(5)\n"
+      "BasicBlock 2, pred: 1\n"
+      "  9: Exit\n";
+
+  // Expected difference after constant folding.
+  diff_t expected_cf_diff = {
+    { "  2: IntConstant [5]\n", "  2: IntConstant\n" },
+    { "  5: Neg(2) [8]\n",      "  12: IntConstant [8]\n" },
+    { "  8: Return(5)\n",       "  8: Return(12)\n" }
+  };
+  std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
+
+  // Check the value of the computed constant.
+  auto check_after_cf = [](HGraph* graph) {
+    HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
+    ASSERT_TRUE(inst->IsIntConstant());
+    ASSERT_EQ(inst->AsIntConstant()->GetValue(), -1);
+  };
+
+  // Expected difference after dead code elimination.
+  diff_t expected_dce_diff = {
+    { "  2: IntConstant\n", removed },
+  };
+  std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
+
+  TestCode(data,
+           expected_before,
+           expected_after_cf,
+           expected_after_dce,
+           check_after_cf);
+}
+
+/**
  * Tiny three-register program exercising int constant folding on addition.
  *
  *                              16-bit
@@ -78,7 +137,7 @@
  *     v2 <- v0 + v1            2.      add-int v2, v0, v1
  *     return v2                4.      return v2
  */
-TEST(ConstantPropagation, IntConstantFoldingOnAddition1) {
+TEST(ConstantFolding, IntConstantFoldingOnAddition1) {
   const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 << 8 | 1 << 12,
     Instruction::CONST_4 | 1 << 8 | 2 << 12,
@@ -97,17 +156,17 @@
     "BasicBlock 2, pred: 1\n"
     "  13: Exit\n";
 
-  // Expected difference after constant propagation.
-  diff_t expected_cp_diff = {
+  // Expected difference after constant folding.
+  diff_t expected_cf_diff = {
     { "  3: IntConstant [9]\n", "  3: IntConstant\n" },
     { "  5: IntConstant [9]\n", "  5: IntConstant\n" },
     { "  9: Add(3, 5) [12]\n",  "  16: IntConstant [12]\n" },
     { "  12: Return(9)\n",      "  12: Return(16)\n" }
   };
-  std::string expected_after_cp = Patch(expected_before, expected_cp_diff);
+  std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
 
   // Check the value of the computed constant.
-  auto check_after_cp = [](HGraph* graph) {
+  auto check_after_cf = [](HGraph* graph) {
     HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
     ASSERT_TRUE(inst->IsIntConstant());
     ASSERT_EQ(inst->AsIntConstant()->GetValue(), 3);
@@ -118,13 +177,13 @@
     { "  3: IntConstant\n", removed },
     { "  5: IntConstant\n", removed }
   };
-  std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
+  std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
 
   TestCode(data,
            expected_before,
-           expected_after_cp,
+           expected_after_cf,
            expected_after_dce,
-           check_after_cp);
+           check_after_cf);
 }
 
 /**
@@ -142,7 +201,7 @@
  *     v2 <- v0 + v1            6.      add-int v2, v0, v1
  *     return v2                8.      return v2
  */
-TEST(ConstantPropagation, IntConstantFoldingOnAddition2) {
+TEST(ConstantFolding, IntConstantFoldingOnAddition2) {
   const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 << 8 | 1 << 12,
     Instruction::CONST_4 | 1 << 8 | 2 << 12,
@@ -169,8 +228,8 @@
     "BasicBlock 2, pred: 1\n"
     "  25: Exit\n";
 
-  // Expected difference after constant propagation.
-  diff_t expected_cp_diff = {
+  // Expected difference after constant folding.
+  diff_t expected_cf_diff = {
     { "  3: IntConstant [9]\n",   "  3: IntConstant\n" },
     { "  5: IntConstant [9]\n",   "  5: IntConstant\n" },
     { "  11: IntConstant [17]\n", "  11: IntConstant\n" },
@@ -180,10 +239,10 @@
     { "  21: Add(9, 17) [24]\n",  "  30: IntConstant [24]\n" },
     { "  24: Return(21)\n",       "  24: Return(30)\n" }
   };
-  std::string expected_after_cp = Patch(expected_before, expected_cp_diff);
+  std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
 
   // Check the values of the computed constants.
-  auto check_after_cp = [](HGraph* graph) {
+  auto check_after_cf = [](HGraph* graph) {
     HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction();
     ASSERT_TRUE(inst1->IsIntConstant());
     ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 3);
@@ -204,13 +263,13 @@
     { "  28: IntConstant\n", removed },
     { "  29: IntConstant\n", removed }
   };
-  std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
+  std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
 
   TestCode(data,
            expected_before,
-           expected_after_cp,
+           expected_after_cf,
            expected_after_dce,
-           check_after_cp);
+           check_after_cf);
 }
 
 /**
@@ -224,7 +283,7 @@
  *     v2 <- v0 - v1            2.      sub-int v2, v0, v1
  *     return v2                4.      return v2
  */
-TEST(ConstantPropagation, IntConstantFoldingOnSubtraction) {
+TEST(ConstantFolding, IntConstantFoldingOnSubtraction) {
   const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 << 8 | 3 << 12,
     Instruction::CONST_4 | 1 << 8 | 2 << 12,
@@ -243,17 +302,17 @@
     "BasicBlock 2, pred: 1\n"
     "  13: Exit\n";
 
-  // Expected difference after constant propagation.
-  diff_t expected_cp_diff = {
+  // Expected difference after constant folding.
+  diff_t expected_cf_diff = {
     { "  3: IntConstant [9]\n", "  3: IntConstant\n" },
     { "  5: IntConstant [9]\n", "  5: IntConstant\n" },
     { "  9: Sub(3, 5) [12]\n",  "  16: IntConstant [12]\n" },
     { "  12: Return(9)\n",      "  12: Return(16)\n" }
   };
-  std::string expected_after_cp = Patch(expected_before, expected_cp_diff);
+  std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
 
   // Check the value of the computed constant.
-  auto check_after_cp = [](HGraph* graph) {
+  auto check_after_cf = [](HGraph* graph) {
     HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
     ASSERT_TRUE(inst->IsIntConstant());
     ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
@@ -264,13 +323,13 @@
     { "  3: IntConstant\n", removed },
     { "  5: IntConstant\n", removed }
   };
-  std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
+  std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
 
   TestCode(data,
            expected_before,
-           expected_after_cp,
+           expected_after_cf,
            expected_after_dce,
-           check_after_cp);
+           check_after_cf);
 }
 
 #define SIX_REGISTERS_CODE_ITEM(...)                                     \
@@ -289,7 +348,7 @@
  *       (v0, v1) + (v1, v2)    4.      add-long v4, v0, v2
  *     return (v4, v5)          6.      return-wide v4
  */
-TEST(ConstantPropagation, LongConstantFoldingOnAddition) {
+TEST(ConstantFolding, LongConstantFoldingOnAddition) {
   const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
     Instruction::CONST_WIDE_16 | 0 << 8, 1,
     Instruction::CONST_WIDE_16 | 2 << 8, 2,
@@ -308,17 +367,17 @@
     "BasicBlock 2, pred: 1\n"
     "  16: Exit\n";
 
-  // Expected difference after constant propagation.
-  diff_t expected_cp_diff = {
+  // Expected difference after constant folding.
+  diff_t expected_cf_diff = {
     { "  6: LongConstant [12]\n", "  6: LongConstant\n" },
     { "  8: LongConstant [12]\n", "  8: LongConstant\n" },
     { "  12: Add(6, 8) [15]\n",   "  19: LongConstant [15]\n" },
     { "  15: Return(12)\n",       "  15: Return(19)\n" }
   };
-  std::string expected_after_cp = Patch(expected_before, expected_cp_diff);
+  std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
 
   // Check the value of the computed constant.
-  auto check_after_cp = [](HGraph* graph) {
+  auto check_after_cf = [](HGraph* graph) {
     HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
     ASSERT_TRUE(inst->IsLongConstant());
     ASSERT_EQ(inst->AsLongConstant()->GetValue(), 3);
@@ -329,13 +388,13 @@
     { "  6: LongConstant\n", removed },
     { "  8: LongConstant\n", removed }
   };
-  std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
+  std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
 
   TestCode(data,
            expected_before,
-           expected_after_cp,
+           expected_after_cf,
            expected_after_dce,
-           check_after_cp,
+           check_after_cf,
            Primitive::kPrimLong);
 }
 
@@ -352,7 +411,7 @@
  *       (v0, v1) - (v1, v2)    4.      sub-long v4, v0, v2
  *     return (v4, v5)          6.      return-wide v4
  */
-TEST(ConstantPropagation, LongConstantFoldingOnSubtraction) {
+TEST(ConstantFolding, LongConstantFoldingOnSubtraction) {
   const uint16_t data[] = SIX_REGISTERS_CODE_ITEM(
     Instruction::CONST_WIDE_16 | 0 << 8, 3,
     Instruction::CONST_WIDE_16 | 2 << 8, 2,
@@ -371,17 +430,17 @@
     "BasicBlock 2, pred: 1\n"
     "  16: Exit\n";
 
-  // Expected difference after constant propagation.
-  diff_t expected_cp_diff = {
+  // Expected difference after constant folding.
+  diff_t expected_cf_diff = {
     { "  6: LongConstant [12]\n", "  6: LongConstant\n" },
     { "  8: LongConstant [12]\n", "  8: LongConstant\n" },
     { "  12: Sub(6, 8) [15]\n",   "  19: LongConstant [15]\n" },
     { "  15: Return(12)\n",       "  15: Return(19)\n" }
   };
-  std::string expected_after_cp = Patch(expected_before, expected_cp_diff);
+  std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
 
   // Check the value of the computed constant.
-  auto check_after_cp = [](HGraph* graph) {
+  auto check_after_cf = [](HGraph* graph) {
     HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
     ASSERT_TRUE(inst->IsLongConstant());
     ASSERT_EQ(inst->AsLongConstant()->GetValue(), 1);
@@ -392,13 +451,13 @@
     { "  6: LongConstant\n", removed },
     { "  8: LongConstant\n", removed }
   };
-  std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
+  std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
 
   TestCode(data,
            expected_before,
-           expected_after_cp,
+           expected_after_cf,
            expected_after_dce,
-           check_after_cp,
+           check_after_cf,
            Primitive::kPrimLong);
 }
 
@@ -424,7 +483,7 @@
  * L3: v2 <- v1 + 4             11.     add-int/lit16 v2, v1, #+4
  *     return v2                13.     return v2
  */
-TEST(ConstantPropagation, IntConstantFoldingAndJumps) {
+TEST(ConstantFolding, IntConstantFoldingAndJumps) {
   const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 0 << 8 | 0 << 12,
     Instruction::CONST_4 | 1 << 8 | 1 << 12,
@@ -462,8 +521,8 @@
     "BasicBlock 5, pred: 4\n"
     "  29: Exit\n";
 
-  // Expected difference after constant propagation.
-  diff_t expected_cp_diff = {
+  // Expected difference after constant folding.
+  diff_t expected_cf_diff = {
     { "  3: IntConstant [9]\n",   "  3: IntConstant\n" },
     { "  5: IntConstant [9]\n",   "  5: IntConstant []\n" },
     { "  13: IntConstant [14]\n", "  13: IntConstant\n" },
@@ -475,10 +534,10 @@
     { "  25: Add(14, 24) [28]\n", "  35: IntConstant [28]\n" },
     { "  28: Return(25)\n",       "  28: Return(35)\n"}
   };
-  std::string expected_after_cp = Patch(expected_before, expected_cp_diff);
+  std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
 
   // Check the values of the computed constants.
-  auto check_after_cp = [](HGraph* graph) {
+  auto check_after_cf = [](HGraph* graph) {
     HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction();
     ASSERT_TRUE(inst1->IsIntConstant());
     ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 1);
@@ -501,13 +560,13 @@
     { "  24: IntConstant\n",    removed },
     { "  34: IntConstant\n",    removed },
   };
-  std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
+  std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
 
   TestCode(data,
            expected_before,
-           expected_after_cp,
+           expected_after_cf,
            expected_after_dce,
-           check_after_cp);
+           check_after_cf);
 }
 
 
@@ -524,7 +583,7 @@
  * L1: v2 <- v0 + v1            5.      add-int v2, v0, v1
  *     return-void              7.      return
  */
-TEST(ConstantPropagation, ConstantCondition) {
+TEST(ConstantFolding, ConstantCondition) {
   const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 1 << 8 | 1 << 12,
     Instruction::CONST_4 | 0 << 8 | 0 << 12,
@@ -553,17 +612,17 @@
     "BasicBlock 5, pred: 1, succ: 3\n"
     "  21: Goto 3\n";
 
-  // Expected difference after constant propagation.
-  diff_t expected_cp_diff = {
+  // Expected difference after constant folding.
+  diff_t expected_cf_diff = {
     { "  3: IntConstant [15, 22, 8]\n",      "  3: IntConstant [15, 22]\n" },
     { "  5: IntConstant [22, 8]\n",          "  5: IntConstant [22]\n" },
     { "  8: GreaterThanOrEqual(3, 5) [9]\n", "  23: IntConstant [9]\n" },
     { "  9: If(8)\n",                        "  9: If(23)\n" }
   };
-  std::string expected_after_cp = Patch(expected_before, expected_cp_diff);
+  std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
 
   // Check the values of the computed constants.
-  auto check_after_cp = [](HGraph* graph) {
+  auto check_after_cf = [](HGraph* graph) {
     HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
     ASSERT_TRUE(inst->IsIntConstant());
     ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
@@ -575,13 +634,13 @@
     { "  22: Phi(3, 5) [15]\n",      "  22: Phi(3, 5)\n" },
     { "  15: Add(22, 3)\n",          removed }
   };
-  std::string expected_after_dce = Patch(expected_after_cp, expected_dce_diff);
+  std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
 
   TestCode(data,
            expected_before,
-           expected_after_cp,
+           expected_after_cf,
            expected_after_dce,
-           check_after_cp);
+           check_after_cf);
 }
 
 }  // namespace art
diff --git a/compiler/optimizing/constant_propagation.h b/compiler/optimizing/constant_propagation.h
deleted file mode 100644
index 0729881..0000000
--- a/compiler/optimizing/constant_propagation.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2014 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_COMPILER_OPTIMIZING_CONSTANT_PROPAGATION_H_
-#define ART_COMPILER_OPTIMIZING_CONSTANT_PROPAGATION_H_
-
-#include "nodes.h"
-
-namespace art {
-
-/**
- * Optimization pass performing a simple constant propagation on the
- * SSA form.
- */
-class ConstantPropagation : public ValueObject {
- public:
-  explicit ConstantPropagation(HGraph* graph)
-    : graph_(graph) {}
-
-  void Run();
-
- private:
-  HGraph* const graph_;
-
-  DISALLOW_COPY_AND_ASSIGN(ConstantPropagation);
-};
-
-}  // namespace art
-
-#endif  // ART_COMPILER_OPTIMIZING_CONSTANT_PROPAGATION_H_
diff --git a/compiler/optimizing/dead_code_elimination.cc b/compiler/optimizing/dead_code_elimination.cc
index fe2adc7..fc3dd01 100644
--- a/compiler/optimizing/dead_code_elimination.cc
+++ b/compiler/optimizing/dead_code_elimination.cc
@@ -20,7 +20,7 @@
 
 namespace art {
 
-void DeadCodeElimination::Run() {
+void HDeadCodeElimination::Run() {
   // Process basic blocks in post-order in the dominator tree, so that
   // a dead instruction depending on another dead instruction is
   // removed.
@@ -35,7 +35,10 @@
     for (i.Advance(); !i.Done(); i.Advance()) {
       HInstruction* inst = i.Current();
       DCHECK(!inst->IsControlFlow());
-      if (!inst->HasSideEffects() && !inst->HasUses() && !inst->IsSuspendCheck()) {
+      if (!inst->HasSideEffects()
+          && !inst->CanThrow()
+          && !inst->IsSuspendCheck()
+          && !inst->HasUses()) {
         block->RemoveInstruction(inst);
       }
     }
diff --git a/compiler/optimizing/dead_code_elimination.h b/compiler/optimizing/dead_code_elimination.h
index 48739be..a4446ae 100644
--- a/compiler/optimizing/dead_code_elimination.h
+++ b/compiler/optimizing/dead_code_elimination.h
@@ -18,6 +18,7 @@
 #define ART_COMPILER_OPTIMIZING_DEAD_CODE_ELIMINATION_H_
 
 #include "nodes.h"
+#include "optimization.h"
 
 namespace art {
 
@@ -25,17 +26,18 @@
  * Optimization pass performing dead code elimination (removal of
  * unused variables/instructions) on the SSA form.
  */
-class DeadCodeElimination : public ValueObject {
+class HDeadCodeElimination : public HOptimization {
  public:
-  explicit DeadCodeElimination(HGraph* graph)
-      : graph_(graph) {}
+  HDeadCodeElimination(HGraph* graph, const HGraphVisualizer& visualizer)
+      : HOptimization(graph, true, kDeadCodeEliminationPassName, visualizer) {}
 
-  void Run();
+  virtual void Run() OVERRIDE;
+
+  static constexpr const char* kDeadCodeEliminationPassName =
+    "dead_code_elimination";
 
  private:
-  HGraph* const graph_;
-
-  DISALLOW_COPY_AND_ASSIGN(DeadCodeElimination);
+  DISALLOW_COPY_AND_ASSIGN(HDeadCodeElimination);
 };
 
 }  // namespace art
diff --git a/compiler/optimizing/dead_code_elimination_test.cc b/compiler/optimizing/dead_code_elimination_test.cc
index 245bcb2..0c68074 100644
--- a/compiler/optimizing/dead_code_elimination_test.cc
+++ b/compiler/optimizing/dead_code_elimination_test.cc
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
+#include "code_generator_x86.h"
 #include "dead_code_elimination.h"
-#include "pretty_printer.h"
 #include "graph_checker.h"
 #include "optimizing_unit_test.h"
+#include "pretty_printer.h"
 
 #include "gtest/gtest.h"
 
@@ -39,16 +40,17 @@
   std::string actual_before = printer_before.str();
   ASSERT_EQ(actual_before, expected_before);
 
-  DeadCodeElimination(graph).Run();
+  x86::CodeGeneratorX86 codegen(graph);
+  HGraphVisualizer visualizer(nullptr, graph, codegen, "");
+  HDeadCodeElimination(graph, visualizer).Run();
+  SSAChecker ssa_checker(&allocator, graph);
+  ssa_checker.Run();
+  ASSERT_TRUE(ssa_checker.IsValid());
 
   StringPrettyPrinter printer_after(graph);
   printer_after.VisitInsertionOrder();
   std::string actual_after = printer_after.str();
   ASSERT_EQ(actual_after, expected_after);
-
-  SSAChecker ssa_checker(&allocator, graph);
-  ssa_checker.VisitInsertionOrder();
-  ASSERT_TRUE(ssa_checker.IsValid());
 }
 
 
@@ -94,6 +96,7 @@
     "BasicBlock 5, pred: 1, succ: 3\n"
     "  21: Goto 3\n";
 
+  // Expected difference after dead code elimination.
   diff_t expected_diff = {
     { "  3: IntConstant [15, 22, 8]\n", "  3: IntConstant [22, 8]\n" },
     { "  22: Phi(3, 5) [15]\n",         "  22: Phi(3, 5)\n" },
@@ -164,7 +167,7 @@
     "BasicBlock 5, pred: 4\n"
     "  28: Exit\n";
 
-  // Expected difference after constant propagation.
+  // Expected difference after dead code elimination.
   diff_t expected_diff = {
     { "  13: IntConstant [14]\n", removed },
     { "  24: IntConstant [25]\n", removed },
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index 589b44a..743ffc4 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -264,21 +264,38 @@
 void SSAChecker::VisitInstruction(HInstruction* instruction) {
   super_type::VisitInstruction(instruction);
 
-  // Ensure an instruction dominates all its uses (or in the present
-  // case, that all uses of an instruction (used as input) are
-  // dominated by its definition).
-  for (HInputIterator input_it(instruction); !input_it.Done();
-       input_it.Advance()) {
-    HInstruction* input = input_it.Current();
-    if (!input->Dominates(instruction)) {
+  // Ensure an instruction dominates all its uses.
+  for (HUseIterator<HInstruction> use_it(instruction->GetUses());
+       !use_it.Done(); use_it.Advance()) {
+    HInstruction* use = use_it.Current()->GetUser();
+    if (!use->IsPhi() && !instruction->StrictlyDominates(use)) {
       std::stringstream error;
-      error << "Instruction " << input->GetId()
-            << " in block " << input->GetBlock()->GetBlockId()
-            << " does not dominate use " << instruction->GetId()
-            << " in block " << current_block_->GetBlockId() << ".";
+      error << "Instruction " << instruction->GetId()
+            << " in block " << current_block_->GetBlockId()
+            << " does not dominate use " << use->GetId()
+            << " in block " << use->GetBlock()->GetBlockId() << ".";
       errors_.Insert(error.str());
     }
   }
+
+  // Ensure an instruction having an environment is dominated by the
+  // instructions contained in the environment.
+  HEnvironment* environment = instruction->GetEnvironment();
+  if (environment != nullptr) {
+    for (size_t i = 0, e = environment->Size(); i < e; ++i) {
+      HInstruction* env_instruction = environment->GetInstructionAt(i);
+      if (env_instruction != nullptr
+          && !env_instruction->StrictlyDominates(instruction)) {
+        std::stringstream error;
+        error << "Instruction " << env_instruction->GetId()
+              << " in environment of instruction " << instruction->GetId()
+              << " from block " << current_block_->GetBlockId()
+              << " does not dominate instruction " << instruction->GetId()
+              << ".";
+        errors_.Insert(error.str());
+      }
+    }
+  }
 }
 
 void SSAChecker::VisitPhi(HPhi* phi) {
diff --git a/compiler/optimizing/graph_checker.h b/compiler/optimizing/graph_checker.h
index 34a770b..badf21d 100644
--- a/compiler/optimizing/graph_checker.h
+++ b/compiler/optimizing/graph_checker.h
@@ -19,15 +19,22 @@
 
 #include "nodes.h"
 
+#include <ostream>
+
 namespace art {
 
 // A control-flow graph visitor performing various checks.
 class GraphChecker : public HGraphVisitor {
  public:
-  GraphChecker(ArenaAllocator* allocator, HGraph* graph)
+  GraphChecker(ArenaAllocator* allocator, HGraph* graph,
+               const char* dump_prefix = "art::GraphChecker: ")
     : HGraphVisitor(graph),
       allocator_(allocator),
-      errors_(allocator, 0) {}
+      errors_(allocator, 0),
+      dump_prefix_(dump_prefix) {}
+
+  // Check the whole graph (in insertion order).
+  virtual void Run() { VisitInsertionOrder(); }
 
   // Check `block`.
   virtual void VisitBasicBlock(HBasicBlock* block) OVERRIDE;
@@ -45,6 +52,13 @@
     return errors_;
   }
 
+  // Print detected errors on output stream `os`.
+  void Dump(std::ostream& os) const {
+    for (size_t i = 0, e = errors_.Size(); i < e; ++i) {
+      os << dump_prefix_ << errors_.Get(i) << std::endl;
+    }
+  }
+
  protected:
   ArenaAllocator* const allocator_;
   // The block currently visited.
@@ -53,6 +67,9 @@
   GrowableArray<std::string> errors_;
 
  private:
+  // String displayed before dumped errors.
+  const char* const dump_prefix_;
+
   DISALLOW_COPY_AND_ASSIGN(GraphChecker);
 };
 
@@ -63,7 +80,15 @@
   typedef GraphChecker super_type;
 
   SSAChecker(ArenaAllocator* allocator, HGraph* graph)
-    : GraphChecker(allocator, graph) {}
+    : GraphChecker(allocator, graph, "art::SSAChecker: ") {}
+
+  // Check the whole graph (in reverse post-order).
+  virtual void Run() {
+    // VisitReversePostOrder is used instead of VisitInsertionOrder,
+    // as the latter might visit dead blocks removed by the dominator
+    // computation.
+    VisitReversePostOrder();
+  }
 
   // Perform SSA form checks on `block`.
   virtual void VisitBasicBlock(HBasicBlock* block) OVERRIDE;
diff --git a/compiler/optimizing/graph_checker_test.cc b/compiler/optimizing/graph_checker_test.cc
index ea06920..39def82 100644
--- a/compiler/optimizing/graph_checker_test.cc
+++ b/compiler/optimizing/graph_checker_test.cc
@@ -51,7 +51,7 @@
   ASSERT_NE(graph, nullptr);
 
   GraphChecker graph_checker(&allocator, graph);
-  graph_checker.VisitInsertionOrder();
+  graph_checker.Run();
   ASSERT_TRUE(graph_checker.IsValid());
 }
 
@@ -65,7 +65,7 @@
   graph->TransformToSSA();
 
   SSAChecker ssa_checker(&allocator, graph);
-  ssa_checker.VisitInsertionOrder();
+  ssa_checker.Run();
   ASSERT_TRUE(ssa_checker.IsValid());
 }
 
@@ -113,13 +113,13 @@
 
   HGraph* graph = CreateSimpleCFG(&allocator);
   GraphChecker graph_checker(&allocator, graph);
-  graph_checker.VisitInsertionOrder();
+  graph_checker.Run();
   ASSERT_TRUE(graph_checker.IsValid());
 
   // Remove the entry block from the exit block's predecessors, to create an
   // inconsistent successor/predecessor relation.
   graph->GetExitBlock()->RemovePredecessor(graph->GetEntryBlock());
-  graph_checker.VisitInsertionOrder();
+  graph_checker.Run();
   ASSERT_FALSE(graph_checker.IsValid());
 }
 
@@ -131,7 +131,7 @@
 
   HGraph* graph = CreateSimpleCFG(&allocator);
   GraphChecker graph_checker(&allocator, graph);
-  graph_checker.VisitInsertionOrder();
+  graph_checker.Run();
   ASSERT_TRUE(graph_checker.IsValid());
 
   // Remove the sole instruction of the exit block (composed of a
@@ -141,7 +141,7 @@
   HInstruction* last_inst = exit_block->GetLastInstruction();
   exit_block->RemoveInstruction(last_inst);
 
-  graph_checker.VisitInsertionOrder();
+  graph_checker.Run();
   ASSERT_FALSE(graph_checker.IsValid());
 }
 
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index b4eb89d..4ed2156 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -120,13 +120,11 @@
     output_<< std::endl;
   }
 
-  void DumpLocation(Location location, Primitive::Type type) {
+  void DumpLocation(Location location) {
     if (location.IsRegister()) {
-      if (type == Primitive::kPrimDouble || type == Primitive::kPrimFloat) {
-        codegen_.DumpFloatingPointRegister(output_, location.reg());
-      } else {
-        codegen_.DumpCoreRegister(output_, location.reg());
-      }
+      codegen_.DumpCoreRegister(output_, location.reg());
+    } else if (location.IsFpuRegister()) {
+      codegen_.DumpFloatingPointRegister(output_, location.reg());
     } else if (location.IsConstant()) {
       output_ << "constant";
       HConstant* constant = location.GetConstant();
@@ -150,9 +148,9 @@
     output_ << " (";
     for (size_t i = 0, e = instruction->NumMoves(); i < e; ++i) {
       MoveOperands* move = instruction->MoveOperandsAt(i);
-      DumpLocation(move->GetSource(), Primitive::kPrimInt);
+      DumpLocation(move->GetSource());
       output_ << " -> ";
-      DumpLocation(move->GetDestination(), Primitive::kPrimInt);
+      DumpLocation(move->GetDestination());
       if (i + 1 != e) {
         output_ << ", ";
       }
@@ -183,13 +181,13 @@
       if (locations != nullptr) {
         output_ << " ( ";
         for (size_t i = 0; i < instruction->InputCount(); ++i) {
-          DumpLocation(locations->InAt(i), instruction->InputAt(i)->GetType());
+          DumpLocation(locations->InAt(i));
           output_ << " ";
         }
         output_ << ")";
         if (locations->Out().IsValid()) {
           output_ << " -> ";
-          DumpLocation(locations->Out(), instruction->GetType());
+          DumpLocation(locations->Out());
         }
       }
       output_ << " (liveness: " << instruction->GetLifetimePosition() << ")";
@@ -309,7 +307,7 @@
   printer.EndTag("compilation");
 }
 
-void HGraphVisualizer::DumpGraph(const char* pass_name) {
+void HGraphVisualizer::DumpGraph(const char* pass_name) const {
   if (!is_enabled_) {
     return;
   }
diff --git a/compiler/optimizing/graph_visualizer.h b/compiler/optimizing/graph_visualizer.h
index f17ba3b..4d8bec2 100644
--- a/compiler/optimizing/graph_visualizer.h
+++ b/compiler/optimizing/graph_visualizer.h
@@ -17,6 +17,8 @@
 #ifndef ART_COMPILER_OPTIMIZING_GRAPH_VISUALIZER_H_
 #define ART_COMPILER_OPTIMIZING_GRAPH_VISUALIZER_H_
 
+#include <ostream>
+
 #include "base/value_object.h"
 
 namespace art {
@@ -61,7 +63,7 @@
    * If this visualizer is enabled, emit the compilation information
    * in `output_`.
    */
-  void DumpGraph(const char* pass_name);
+  void DumpGraph(const char* pass_name) const;
 
  private:
   std::ostream* const output_;
diff --git a/compiler/optimizing/gvn.h b/compiler/optimizing/gvn.h
index 41b3ceb..a98d714 100644
--- a/compiler/optimizing/gvn.h
+++ b/compiler/optimizing/gvn.h
@@ -17,7 +17,6 @@
 #ifndef ART_COMPILER_OPTIMIZING_GVN_H_
 #define ART_COMPILER_OPTIMIZING_GVN_H_
 
-#include <gtest/gtest.h>
 #include "nodes.h"
 
 namespace art {
@@ -221,7 +220,7 @@
   // Mark visisted blocks. Only used for debugging.
   GrowableArray<bool> visited_;
 
-  FRIEND_TEST(GVNTest, LoopSideEffects);
+  ART_FRIEND_TEST(GVNTest, LoopSideEffects);
   DISALLOW_COPY_AND_ASSIGN(GlobalValueNumberer);
 };
 
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 2d9e35c..29eabe7 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -50,7 +50,7 @@
       // Replace (bool_value == 0) with !bool_value
       DCHECK_EQ(input2->AsIntConstant()->GetValue(), 0);
       equal->GetBlock()->ReplaceAndRemoveInstructionWith(
-          equal, new (GetGraph()->GetArena()) HNot(input1));
+          equal, new (GetGraph()->GetArena()) HNot(Primitive::kPrimBoolean, input1));
     }
   }
 }
diff --git a/compiler/optimizing/live_ranges_test.cc b/compiler/optimizing/live_ranges_test.cc
index eafc3e1..89c9495 100644
--- a/compiler/optimizing/live_ranges_test.cc
+++ b/compiler/optimizing/live_ranges_test.cc
@@ -73,9 +73,9 @@
   LiveRange* range = interval->GetFirstRange();
   ASSERT_EQ(2u, range->GetStart());
   // Last use is the return instruction.
-  ASSERT_EQ(9u, range->GetEnd());
+  ASSERT_EQ(8u, range->GetEnd());
   HBasicBlock* block = graph->GetBlocks().Get(1);
-  ASSERT_TRUE(block->GetLastInstruction()->AsReturn() != nullptr);
+  ASSERT_TRUE(block->GetLastInstruction()->IsReturn());
   ASSERT_EQ(8u, block->GetLastInstruction()->GetLifetimePosition());
   ASSERT_TRUE(range->GetNext() == nullptr);
 }
@@ -119,9 +119,9 @@
   LiveRange* range = interval->GetFirstRange();
   ASSERT_EQ(2u, range->GetStart());
   // Last use is the return instruction.
-  ASSERT_EQ(23u, range->GetEnd());
+  ASSERT_EQ(22u, range->GetEnd());
   HBasicBlock* block = graph->GetBlocks().Get(3);
-  ASSERT_TRUE(block->GetLastInstruction()->AsReturn() != nullptr);
+  ASSERT_TRUE(block->GetLastInstruction()->IsReturn());
   ASSERT_EQ(22u, block->GetLastInstruction()->GetLifetimePosition());
   ASSERT_TRUE(range->GetNext() == nullptr);
 }
@@ -193,7 +193,7 @@
   range = interval->GetFirstRange();
   ASSERT_EQ(22u, liveness.GetInstructionFromSsaIndex(2)->GetLifetimePosition());
   ASSERT_EQ(22u, range->GetStart());
-  ASSERT_EQ(25u, range->GetEnd());
+  ASSERT_EQ(24u, range->GetEnd());
   ASSERT_TRUE(range->GetNext() == nullptr);
 }
 
@@ -263,7 +263,7 @@
   range = interval->GetFirstRange();
   // The instruction is live until the return instruction after the loop.
   ASSERT_EQ(6u, range->GetStart());
-  ASSERT_EQ(27u, range->GetEnd());
+  ASSERT_EQ(26u, range->GetEnd());
   ASSERT_TRUE(range->GetNext() == nullptr);
 
   // Test for the phi.
@@ -271,7 +271,7 @@
   range = interval->GetFirstRange();
   // Instruction is consumed by the if.
   ASSERT_EQ(14u, range->GetStart());
-  ASSERT_EQ(16u, range->GetEnd());
+  ASSERT_EQ(17u, range->GetEnd());
   ASSERT_TRUE(range->GetNext() == nullptr);
 }
 
@@ -338,7 +338,7 @@
   range = range->GetNext();
   ASSERT_TRUE(range != nullptr);
   ASSERT_EQ(24u, range->GetStart());
-  ASSERT_EQ(27u, range->GetEnd());
+  ASSERT_EQ(26u, range->GetEnd());
 
   // Test for the add instruction.
   HAdd* add = liveness.GetInstructionFromSsaIndex(2)->AsAdd();
@@ -410,7 +410,7 @@
   interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval();
   range = interval->GetFirstRange();
   ASSERT_EQ(4u, range->GetStart());
-  ASSERT_EQ(29u, range->GetEnd());
+  ASSERT_EQ(28u, range->GetEnd());
   ASSERT_TRUE(range->GetNext() == nullptr);
 
   // Test for the first add.
diff --git a/compiler/optimizing/locations.cc b/compiler/optimizing/locations.cc
index 1637484..ed5e260 100644
--- a/compiler/optimizing/locations.cc
+++ b/compiler/optimizing/locations.cc
@@ -25,16 +25,14 @@
       temps_(instruction->GetBlock()->GetGraph()->GetArena(), 0),
       environment_(instruction->GetBlock()->GetGraph()->GetArena(),
                    instruction->EnvironmentSize()),
-      dies_at_entry_(instruction->GetBlock()->GetGraph()->GetArena(), instruction->InputCount()),
+      output_overlaps_(true),
       call_kind_(call_kind),
       stack_mask_(nullptr),
       register_mask_(0),
       live_registers_() {
   inputs_.SetSize(instruction->InputCount());
-  dies_at_entry_.SetSize(instruction->InputCount());
   for (size_t i = 0; i < instruction->InputCount(); ++i) {
     inputs_.Put(i, Location());
-    dies_at_entry_.Put(i, false);
   }
   environment_.SetSize(instruction->EnvironmentSize());
   for (size_t i = 0; i < instruction->EnvironmentSize(); ++i) {
diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h
index dcf70f2..11bcd78 100644
--- a/compiler/optimizing/locations.h
+++ b/compiler/optimizing/locations.h
@@ -34,7 +34,7 @@
  */
 class Location : public ValueObject {
  public:
-  static constexpr bool kDiesAtEntry = true;
+  static constexpr bool kNoOutputOverlap = false;
 
   enum Kind {
     kInvalid = 0,
@@ -373,8 +373,7 @@
 
   LocationSummary(HInstruction* instruction, CallKind call_kind = kNoCall);
 
-  void SetInAt(uint32_t at, Location location, bool dies_at_entry = false) {
-    dies_at_entry_.Put(at, dies_at_entry);
+  void SetInAt(uint32_t at, Location location) {
     inputs_.Put(at, location);
   }
 
@@ -386,7 +385,8 @@
     return inputs_.Size();
   }
 
-  void SetOut(Location location) {
+  void SetOut(Location location, bool overlaps = true) {
+    output_overlaps_ = overlaps;
     output_ = Location(location);
   }
 
@@ -449,23 +449,30 @@
     return &live_registers_;
   }
 
-  bool InputOverlapsWithOutputOrTemp(uint32_t input, bool is_environment) const {
+  bool InputOverlapsWithOutputOrTemp(uint32_t input_index, bool is_environment) const {
     if (is_environment) return true;
-    Location location = Out();
-    if (input == 0 && location.IsUnallocated() && location.GetPolicy() == Location::kSameAsFirstInput) {
+    if ((input_index == 0)
+        && output_.IsUnallocated()
+        && (output_.GetPolicy() == Location::kSameAsFirstInput)) {
       return false;
     }
-    if (dies_at_entry_.Get(input)) {
+    if (inputs_.Get(input_index).IsRegister() || inputs_.Get(input_index).IsFpuRegister()) {
       return false;
     }
     return true;
   }
 
+  bool OutputOverlapsWithInputs() const {
+    return output_overlaps_;
+  }
+
  private:
   GrowableArray<Location> inputs_;
   GrowableArray<Location> temps_;
   GrowableArray<Location> environment_;
-  GrowableArray<bool> dies_at_entry_;
+  // Whether the output overlaps with any of the inputs. If it overlaps, then it cannot
+  // share the same register as the inputs.
+  bool output_overlaps_;
   Location output_;
   const CallKind call_kind_;
 
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 3a0b40c..d624ad5 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -317,8 +317,8 @@
 }
 
 void HBasicBlock::InsertInstructionBefore(HInstruction* instruction, HInstruction* cursor) {
-  DCHECK(cursor->AsPhi() == nullptr);
-  DCHECK(instruction->AsPhi() == nullptr);
+  DCHECK(!cursor->IsPhi());
+  DCHECK(!instruction->IsPhi());
   DCHECK_EQ(instruction->GetId(), -1);
   DCHECK_NE(cursor->GetId(), -1);
   DCHECK_EQ(cursor->GetBlock(), this);
@@ -363,6 +363,25 @@
   Add(&phis_, this, phi);
 }
 
+void HBasicBlock::InsertPhiAfter(HPhi* phi, HPhi* cursor) {
+  DCHECK_EQ(phi->GetId(), -1);
+  DCHECK_NE(cursor->GetId(), -1);
+  DCHECK_EQ(cursor->GetBlock(), this);
+  if (cursor->next_ == nullptr) {
+    cursor->next_ = phi;
+    phi->previous_ = cursor;
+    DCHECK(phi->next_ == nullptr);
+  } else {
+    phi->next_ = cursor->next_;
+    phi->previous_ = cursor;
+    cursor->next_ = phi;
+    phi->next_->previous_ = phi;
+  }
+  phi->SetBlock(this);
+  phi->SetId(GetGraph()->GetNextInstructionId());
+  UpdateInputsUsers(phi);
+}
+
 static void Remove(HInstructionList* instruction_list,
                    HBasicBlock* block,
                    HInstruction* instruction) {
@@ -472,7 +491,11 @@
   return true;
 }
 
-bool HInstruction::Dominates(HInstruction* other_instruction) const {
+bool HInstruction::StrictlyDominates(HInstruction* other_instruction) const {
+  if (other_instruction == this) {
+    // An instruction does not strictly dominate itself.
+    return false;
+  }
   HBasicBlock* block = GetBlock();
   HBasicBlock* other_block = other_instruction->GetBlock();
   if (block != other_block) {
@@ -527,6 +550,12 @@
   env_uses_ = nullptr;
 }
 
+void HInstruction::ReplaceInput(HInstruction* replacement, size_t index) {
+  InputAt(index)->RemoveUser(this, index);
+  SetRawInputAt(index, replacement);
+  replacement->AddUseAt(this, index);
+}
+
 size_t HInstruction::EnvironmentSize() const {
   return HasEnvironment() ? environment_->Size() : 0;
 }
@@ -553,6 +582,12 @@
   }
 }
 
+void HGraphVisitor::VisitReversePostOrder() {
+  for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
+    VisitBasicBlock(it.Current());
+  }
+}
+
 void HGraphVisitor::VisitBasicBlock(HBasicBlock* block) {
   for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
     it.Current()->Accept(this);
@@ -562,15 +597,30 @@
   }
 }
 
-HConstant* HBinaryOperation::TryStaticEvaluation(ArenaAllocator* allocator) const {
+HConstant* HUnaryOperation::TryStaticEvaluation() const {
+  if (GetInput()->IsIntConstant()) {
+    int32_t value = Evaluate(GetInput()->AsIntConstant()->GetValue());
+    return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
+  } else if (GetInput()->IsLongConstant()) {
+    // TODO: Implement static evaluation of long unary operations.
+    //
+    // Do not exit with a fatal condition here.  Instead, simply
+    // return `nullptr' to notify the caller that this instruction
+    // cannot (yet) be statically evaluated.
+    return nullptr;
+  }
+  return nullptr;
+}
+
+HConstant* HBinaryOperation::TryStaticEvaluation() const {
   if (GetLeft()->IsIntConstant() && GetRight()->IsIntConstant()) {
     int32_t value = Evaluate(GetLeft()->AsIntConstant()->GetValue(),
                              GetRight()->AsIntConstant()->GetValue());
-    return new(allocator) HIntConstant(value);
+    return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
   } else if (GetLeft()->IsLongConstant() && GetRight()->IsLongConstant()) {
     int64_t value = Evaluate(GetLeft()->AsLongConstant()->GetValue(),
                              GetRight()->AsLongConstant()->GetValue());
-    return new(allocator) HLongConstant(value);
+    return new(GetBlock()->GetGraph()->GetArena()) HLongConstant(value);
   }
   return nullptr;
 }
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 677a4f8..7adb840 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -399,6 +399,7 @@
   void ReplaceAndRemoveInstructionWith(HInstruction* initial,
                                        HInstruction* replacement);
   void AddPhi(HPhi* phi);
+  void InsertPhiAfter(HPhi* instruction, HPhi* cursor);
   void RemovePhi(HPhi* phi);
 
   bool IsLoopHeader() const {
@@ -484,7 +485,7 @@
   M(Local, Instruction)                                                 \
   M(LongConstant, Constant)                                             \
   M(NewInstance, Instruction)                                           \
-  M(Not, Instruction)                                                   \
+  M(Not, UnaryOperation)                                                \
   M(ParameterValue, Instruction)                                        \
   M(ParallelMove, Instruction)                                          \
   M(Phi, Instruction)                                                   \
@@ -502,11 +503,17 @@
   M(NullCheck, Instruction)                                             \
   M(Temporary, Instruction)                                             \
   M(SuspendCheck, Instruction)                                          \
+  M(Mul, BinaryOperation)                                               \
+  M(Neg, UnaryOperation)                                                \
+  M(FloatConstant, Constant)                                            \
+  M(DoubleConstant, Constant)                                           \
+  M(NewArray, Instruction)                                              \
 
 #define FOR_EACH_INSTRUCTION(M)                                         \
   FOR_EACH_CONCRETE_INSTRUCTION(M)                                      \
   M(Constant, Instruction)                                              \
-  M(BinaryOperation, Instruction) \
+  M(UnaryOperation, Instruction)                                        \
+  M(BinaryOperation, Instruction)                                       \
   M(Invoke, Instruction)
 
 #define FORWARD_DECLARATION(type, super) class H##type;
@@ -650,6 +657,7 @@
 
   virtual bool NeedsEnvironment() const { return false; }
   virtual bool IsControlFlow() const { return false; }
+  virtual bool CanThrow() const { return false; }
   bool HasSideEffects() const { return side_effects_.HasSideEffects(); }
 
   void AddUseAt(HInstruction* user, size_t index) {
@@ -682,9 +690,10 @@
     return result;
   }
 
-  // Does this instruction dominate `other_instruction`?  Aborts if
-  // this instruction and `other_instruction` are both phis.
-  bool Dominates(HInstruction* other_instruction) const;
+  // Does this instruction strictly dominate `other_instruction`?
+  // Returns false if this instruction and `other_instruction` are the same.
+  // Aborts if this instruction and `other_instruction` are both phis.
+  bool StrictlyDominates(HInstruction* other_instruction) const;
 
   int GetId() const { return id_; }
   void SetId(int id) { id_ = id; }
@@ -705,6 +714,7 @@
   void SetLocations(LocationSummary* locations) { locations_ = locations; }
 
   void ReplaceWith(HInstruction* instruction);
+  void ReplaceInput(HInstruction* replacement, size_t index);
 
   bool HasOnlyOneUse() const {
     return uses_ != nullptr && uses_->GetTail() == nullptr;
@@ -990,8 +1000,8 @@
 
   virtual Primitive::Type GetType() const { return type_; }
 
- private:
-  const Primitive::Type type_;
+ protected:
+  Primitive::Type type_;
 };
 
 // Represents dex's RETURN_VOID opcode. A HReturnVoid is a control flow
@@ -1083,6 +1093,34 @@
   DISALLOW_COPY_AND_ASSIGN(HIf);
 };
 
+class HUnaryOperation : public HExpression<1> {
+ public:
+  HUnaryOperation(Primitive::Type result_type, HInstruction* input)
+      : HExpression(result_type, SideEffects::None()) {
+    SetRawInputAt(0, input);
+  }
+
+  HInstruction* GetInput() const { return InputAt(0); }
+  Primitive::Type GetResultType() const { return GetType(); }
+
+  virtual bool CanBeMoved() const { return true; }
+  virtual bool InstructionDataEquals(HInstruction* other) const { return true; }
+
+  // Try to statically evaluate `operation` and return a HConstant
+  // containing the result of this evaluation.  If `operation` cannot
+  // be evaluated as a constant, return nullptr.
+  HConstant* TryStaticEvaluation() const;
+
+  // Apply this operation to `x`.
+  virtual int32_t Evaluate(int32_t x) const = 0;
+  virtual int64_t Evaluate(int64_t x) const = 0;
+
+  DECLARE_INSTRUCTION(UnaryOperation);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HUnaryOperation);
+};
+
 class HBinaryOperation : public HExpression<2> {
  public:
   HBinaryOperation(Primitive::Type result_type,
@@ -1101,10 +1139,10 @@
   virtual bool CanBeMoved() const { return true; }
   virtual bool InstructionDataEquals(HInstruction* other) const { return true; }
 
-  // Try to statically evaluate `operation` and return an HConstant
+  // Try to statically evaluate `operation` and return a HConstant
   // containing the result of this evaluation.  If `operation` cannot
   // be evaluated as a constant, return nullptr.
-  HConstant* TryStaticEvaluation(ArenaAllocator* allocator) const;
+  HConstant* TryStaticEvaluation() const;
 
   // Apply this operation to `x` and `y`.
   virtual int32_t Evaluate(int32_t x, int32_t y) const = 0;
@@ -1368,6 +1406,48 @@
   DISALLOW_COPY_AND_ASSIGN(HConstant);
 };
 
+class HFloatConstant : public HConstant {
+ public:
+  explicit HFloatConstant(float value) : HConstant(Primitive::kPrimFloat), value_(value) {}
+
+  float GetValue() const { return value_; }
+
+  virtual bool InstructionDataEquals(HInstruction* other) const {
+    return bit_cast<float, int32_t>(other->AsFloatConstant()->value_) ==
+        bit_cast<float, int32_t>(value_);
+  }
+
+  virtual size_t ComputeHashCode() const { return static_cast<size_t>(GetValue()); }
+
+  DECLARE_INSTRUCTION(FloatConstant);
+
+ private:
+  const float value_;
+
+  DISALLOW_COPY_AND_ASSIGN(HFloatConstant);
+};
+
+class HDoubleConstant : public HConstant {
+ public:
+  explicit HDoubleConstant(double value) : HConstant(Primitive::kPrimDouble), value_(value) {}
+
+  double GetValue() const { return value_; }
+
+  virtual bool InstructionDataEquals(HInstruction* other) const {
+    return bit_cast<double, int64_t>(other->AsDoubleConstant()->value_) ==
+        bit_cast<double, int64_t>(value_);
+  }
+
+  virtual size_t ComputeHashCode() const { return static_cast<size_t>(GetValue()); }
+
+  DECLARE_INSTRUCTION(DoubleConstant);
+
+ private:
+  const double value_;
+
+  DISALLOW_COPY_AND_ASSIGN(HDoubleConstant);
+};
+
 // Constants of the type int. Those can be from Dex instructions, or
 // synthesized (for example with the if-eqz instruction).
 class HIntConstant : public HConstant {
@@ -1515,6 +1595,44 @@
   DISALLOW_COPY_AND_ASSIGN(HNewInstance);
 };
 
+class HNeg : public HUnaryOperation {
+ public:
+  explicit HNeg(Primitive::Type result_type, HInstruction* input)
+      : HUnaryOperation(result_type, input) {}
+
+  virtual int32_t Evaluate(int32_t x) const OVERRIDE { return -x; }
+  virtual int64_t Evaluate(int64_t x) const OVERRIDE { return -x; }
+
+  DECLARE_INSTRUCTION(Neg);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HNeg);
+};
+
+class HNewArray : public HExpression<1> {
+ public:
+  HNewArray(HInstruction* length, uint32_t dex_pc, uint16_t type_index)
+      : HExpression(Primitive::kPrimNot, SideEffects::None()),
+        dex_pc_(dex_pc),
+        type_index_(type_index) {
+    SetRawInputAt(0, length);
+  }
+
+  uint32_t GetDexPc() const { return dex_pc_; }
+  uint16_t GetTypeIndex() const { return type_index_; }
+
+  // Calls runtime so needs an environment.
+  virtual bool NeedsEnvironment() const { return true; }
+
+  DECLARE_INSTRUCTION(NewArray);
+
+ private:
+  const uint32_t dex_pc_;
+  const uint16_t type_index_;
+
+  DISALLOW_COPY_AND_ASSIGN(HNewArray);
+};
+
 class HAdd : public HBinaryOperation {
  public:
   HAdd(Primitive::Type result_type, HInstruction* left, HInstruction* right)
@@ -1555,6 +1673,22 @@
   DISALLOW_COPY_AND_ASSIGN(HSub);
 };
 
+class HMul : public HBinaryOperation {
+ public:
+  HMul(Primitive::Type result_type, HInstruction* left, HInstruction* right)
+      : HBinaryOperation(result_type, left, right) {}
+
+  virtual bool IsCommutative() { return true; }
+
+  virtual int32_t Evaluate(int32_t x, int32_t y) const { return x * y; }
+  virtual int64_t Evaluate(int64_t x, int64_t y) const { return x * y; }
+
+  DECLARE_INSTRUCTION(Mul);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HMul);
+};
+
 // The value of a parameter in this method. Its location depends on
 // the calling convention.
 class HParameterValue : public HExpression<0> {
@@ -1574,15 +1708,17 @@
   DISALLOW_COPY_AND_ASSIGN(HParameterValue);
 };
 
-class HNot : public HExpression<1> {
+class HNot : public HUnaryOperation {
  public:
-  explicit HNot(HInstruction* input) : HExpression(Primitive::kPrimBoolean, SideEffects::None()) {
-    SetRawInputAt(0, input);
-  }
+  explicit HNot(Primitive::Type result_type, HInstruction* input)
+      : HUnaryOperation(result_type, input) {}
 
   virtual bool CanBeMoved() const { return true; }
   virtual bool InstructionDataEquals(HInstruction* other) const { return true; }
 
+  virtual int32_t Evaluate(int32_t x) const OVERRIDE { return ~x; }
+  virtual int64_t Evaluate(int64_t x) const OVERRIDE { return ~x; }
+
   DECLARE_INSTRUCTION(Not);
 
  private:
@@ -1642,6 +1778,8 @@
 
   virtual bool NeedsEnvironment() const { return true; }
 
+  virtual bool CanThrow() const { return true; }
+
   uint32_t GetDexPc() const { return dex_pc_; }
 
   DECLARE_INSTRUCTION(NullCheck);
@@ -1729,6 +1867,7 @@
 
   virtual bool CanBeMoved() const { return true; }
   virtual bool InstructionDataEquals(HInstruction* other) const { return true; }
+  void SetType(Primitive::Type type) { type_ = type; }
 
   DECLARE_INSTRUCTION(ArrayGet);
 
@@ -1741,11 +1880,11 @@
   HArraySet(HInstruction* array,
             HInstruction* index,
             HInstruction* value,
-            Primitive::Type component_type,
+            Primitive::Type expected_component_type,
             uint32_t dex_pc)
       : HTemplateInstruction(SideEffects::ChangesSomething()),
         dex_pc_(dex_pc),
-        component_type_(component_type) {
+        expected_component_type_(expected_component_type) {
     SetRawInputAt(0, array);
     SetRawInputAt(1, index);
     SetRawInputAt(2, value);
@@ -1759,13 +1898,24 @@
 
   uint32_t GetDexPc() const { return dex_pc_; }
 
-  Primitive::Type GetComponentType() const { return component_type_; }
+  HInstruction* GetValue() const { return InputAt(2); }
+
+  Primitive::Type GetComponentType() const {
+    // The Dex format does not type floating point index operations. Since the
+    // `expected_component_type_` is set during building and can therefore not
+    // be correct, we also check what is the value type. If it is a floating
+    // point type, we must use that type.
+    Primitive::Type value_type = GetValue()->GetType();
+    return ((value_type == Primitive::kPrimFloat) || (value_type == Primitive::kPrimDouble))
+        ? value_type
+        : expected_component_type_;
+  }
 
   DECLARE_INSTRUCTION(ArraySet);
 
  private:
   const uint32_t dex_pc_;
-  const Primitive::Type component_type_;
+  const Primitive::Type expected_component_type_;
 
   DISALLOW_COPY_AND_ASSIGN(HArraySet);
 };
@@ -1802,6 +1952,8 @@
 
   virtual bool NeedsEnvironment() const { return true; }
 
+  virtual bool CanThrow() const { return true; }
+
   uint32_t GetDexPc() const { return dex_pc_; }
 
   DECLARE_INSTRUCTION(BoundsCheck);
@@ -1956,8 +2108,12 @@
   virtual void VisitInstruction(HInstruction* instruction) {}
   virtual void VisitBasicBlock(HBasicBlock* block);
 
+  // Visit the graph following basic block insertion order.
   void VisitInsertionOrder();
 
+  // Visit the graph following dominator tree reverse post-order.
+  void VisitReversePostOrder();
+
   HGraph* GetGraph() const { return graph_; }
 
   // Visit functions for instruction classes.
@@ -1969,7 +2125,7 @@
 #undef DECLARE_VISIT_INSTRUCTION
 
  private:
-  HGraph* graph_;
+  HGraph* const graph_;
 
   DISALLOW_COPY_AND_ASSIGN(HGraphVisitor);
 };
diff --git a/compiler/optimizing/optimization.cc b/compiler/optimizing/optimization.cc
new file mode 100644
index 0000000..ea98186
--- /dev/null
+++ b/compiler/optimizing/optimization.cc
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 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 "optimization.h"
+
+#include "base/dumpable.h"
+#include "graph_checker.h"
+
+namespace art {
+
+void HOptimization::Execute() {
+  Run();
+  visualizer_.DumpGraph(pass_name_);
+  Check();
+}
+
+void HOptimization::Check() {
+  if (kIsDebugBuild) {
+    if (is_in_ssa_form_) {
+      SSAChecker checker(graph_->GetArena(), graph_);
+      checker.Run();
+      if (!checker.IsValid()) {
+        LOG(FATAL) << Dumpable<SSAChecker>(checker);
+      }
+    } else {
+      GraphChecker checker(graph_->GetArena(), graph_);
+      checker.Run();
+      if (!checker.IsValid()) {
+        LOG(FATAL) << Dumpable<GraphChecker>(checker);
+      }
+    }
+  }
+}
+
+}  // namespace art
diff --git a/compiler/optimizing/optimization.h b/compiler/optimizing/optimization.h
new file mode 100644
index 0000000..59683e2
--- /dev/null
+++ b/compiler/optimizing/optimization.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2014 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_COMPILER_OPTIMIZING_OPTIMIZATION_H_
+#define ART_COMPILER_OPTIMIZING_OPTIMIZATION_H_
+
+#include "graph_visualizer.h"
+#include "nodes.h"
+
+namespace art {
+
+/**
+ * Abstraction to implement an optimization pass.
+ */
+class HOptimization : public ValueObject {
+ public:
+  HOptimization(HGraph* graph,
+                bool is_in_ssa_form,
+                const char* pass_name,
+                const HGraphVisualizer& visualizer)
+      : graph_(graph),
+        is_in_ssa_form_(is_in_ssa_form),
+        pass_name_(pass_name),
+        visualizer_(visualizer) {}
+
+  virtual ~HOptimization() {}
+
+  // Execute the optimization pass.
+  void Execute();
+
+  // Return the name of the pass.
+  const char* GetPassName() const { return pass_name_; }
+
+  // Peform the analysis itself.
+  virtual void Run() = 0;
+
+ private:
+  // Verify the graph; abort if it is not valid.
+  void Check();
+
+ protected:
+  HGraph* const graph_;
+
+ private:
+  // Does the analyzed graph use the SSA form?
+  const bool is_in_ssa_form_;
+  // Optimization pass name.
+  const char* pass_name_;
+  // A graph visualiser invoked after the execution of the optimization
+  // pass if enabled.
+  const HGraphVisualizer& visualizer_;
+
+  DISALLOW_COPY_AND_ASSIGN(HOptimization);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_OPTIMIZING_OPTIMIZATION_H_
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 3cf5a0b..80e9cdb 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -22,6 +22,8 @@
 #include "builder.h"
 #include "code_generator.h"
 #include "compiler.h"
+#include "constant_folding.h"
+#include "dead_code_elimination.h"
 #include "driver/compiler_driver.h"
 #include "driver/dex_compilation_unit.h"
 #include "graph_visualizer.h"
@@ -213,7 +215,10 @@
   }
 
   // Do not attempt to compile on architectures we do not support.
-  if (instruction_set != kX86 && instruction_set != kX86_64 && instruction_set != kThumb2) {
+  if (instruction_set != kArm64 &&
+      instruction_set != kThumb2 &&
+      instruction_set != kX86 &&
+      instruction_set != kX86_64) {
     return nullptr;
   }
 
@@ -261,6 +266,9 @@
     visualizer.DumpGraph("ssa");
     graph->FindNaturalLoops();
 
+    HDeadCodeElimination(graph, visualizer).Execute();
+    HConstantFolding(graph, visualizer).Execute();
+
     SsaRedundantPhiElimination(graph).Run();
     SsaDeadPhiElimination(graph).Run();
     InstructionSimplifier(graph).Run();
diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc
index 8b32262..f95c4a4 100644
--- a/compiler/optimizing/register_allocator.cc
+++ b/compiler/optimizing/register_allocator.cc
@@ -16,6 +16,8 @@
 
 #include "register_allocator.h"
 
+#include <sstream>
+
 #include "base/bit_vector-inl.h"
 #include "code_generator.h"
 #include "ssa_liveness_analysis.h"
@@ -37,18 +39,21 @@
         handled_(allocator, 0),
         active_(allocator, 0),
         inactive_(allocator, 0),
-        physical_register_intervals_(allocator, codegen->GetNumberOfCoreRegisters()),
+        physical_core_register_intervals_(allocator, codegen->GetNumberOfCoreRegisters()),
+        physical_fp_register_intervals_(allocator, codegen->GetNumberOfFloatingPointRegisters()),
         temp_intervals_(allocator, 4),
         spill_slots_(allocator, kDefaultNumberOfSpillSlots),
         safepoints_(allocator, 0),
         processing_core_registers_(false),
         number_of_registers_(-1),
         registers_array_(nullptr),
-        blocked_registers_(codegen->GetBlockedCoreRegisters()),
+        blocked_core_registers_(codegen->GetBlockedCoreRegisters()),
+        blocked_fp_registers_(codegen->GetBlockedFloatingPointRegisters()),
         reserved_out_slots_(0),
         maximum_number_of_live_registers_(0) {
   codegen->SetupBlockedRegisters();
-  physical_register_intervals_.SetSize(codegen->GetNumberOfCoreRegisters());
+  physical_core_register_intervals_.SetSize(codegen->GetNumberOfCoreRegisters());
+  physical_fp_register_intervals_.SetSize(codegen->GetNumberOfFloatingPointRegisters());
   // Always reserve for the current method and the graph's max out registers.
   // TODO: compute it instead.
   reserved_out_slots_ = 1 + codegen->GetGraph()->GetMaximumNumberOfOutVRegs();
@@ -65,8 +70,10 @@
          it.Advance()) {
       HInstruction* current = it.Current();
       if (current->GetType() == Primitive::kPrimLong && instruction_set != kX86_64) return false;
-      if (current->GetType() == Primitive::kPrimFloat) return false;
-      if (current->GetType() == Primitive::kPrimDouble) return false;
+      if ((current->GetType() == Primitive::kPrimFloat || current->GetType() == Primitive::kPrimDouble)
+          && instruction_set != kX86_64) {
+        return false;
+      }
     }
   }
   return true;
@@ -93,14 +100,22 @@
 
 void RegisterAllocator::BlockRegister(Location location,
                                       size_t start,
-                                      size_t end,
-                                      Primitive::Type type) {
+                                      size_t end) {
   int reg = location.reg();
-  LiveInterval* interval = physical_register_intervals_.Get(reg);
+  DCHECK(location.IsRegister() || location.IsFpuRegister());
+  LiveInterval* interval = location.IsRegister()
+      ? physical_core_register_intervals_.Get(reg)
+      : physical_fp_register_intervals_.Get(reg);
+  Primitive::Type type = location.IsRegister()
+      ? Primitive::kPrimInt
+      : Primitive::kPrimDouble;
   if (interval == nullptr) {
     interval = LiveInterval::MakeFixedInterval(allocator_, reg, type);
-    physical_register_intervals_.Put(reg, interval);
-    inactive_.Add(interval);
+    if (location.IsRegister()) {
+      physical_core_register_intervals_.Put(reg, interval);
+    } else {
+      physical_fp_register_intervals_.Put(reg, interval);
+    }
   }
   DCHECK(interval->GetRegister() == reg);
   interval->AddRange(start, end);
@@ -123,8 +138,17 @@
   registers_array_ = allocator_->AllocArray<size_t>(number_of_registers_);
   processing_core_registers_ = true;
   unhandled_ = &unhandled_core_intervals_;
+  for (size_t i = 0, e = physical_core_register_intervals_.Size(); i < e; ++i) {
+    LiveInterval* fixed = physical_core_register_intervals_.Get(i);
+    if (fixed != nullptr) {
+      inactive_.Add(fixed);
+    }
+  }
   LinearScan();
 
+  size_t saved_maximum_number_of_live_registers = maximum_number_of_live_registers_;
+  maximum_number_of_live_registers_ = 0;
+
   inactive_.Reset();
   active_.Reset();
   handled_.Reset();
@@ -133,9 +157,14 @@
   registers_array_ = allocator_->AllocArray<size_t>(number_of_registers_);
   processing_core_registers_ = false;
   unhandled_ = &unhandled_fp_intervals_;
-  // TODO: Enable FP register allocation.
-  DCHECK(unhandled_->IsEmpty());
+  for (size_t i = 0, e = physical_fp_register_intervals_.Size(); i < e; ++i) {
+    LiveInterval* fixed = physical_fp_register_intervals_.Get(i);
+    if (fixed != nullptr) {
+      inactive_.Add(fixed);
+    }
+  }
   LinearScan();
+  maximum_number_of_live_registers_ += saved_maximum_number_of_live_registers;
 }
 
 void RegisterAllocator::ProcessInstruction(HInstruction* instruction) {
@@ -148,8 +177,9 @@
   for (size_t i = 0; i < locations->GetTempCount(); ++i) {
     Location temp = locations->GetTemp(i);
     if (temp.IsRegister()) {
-      BlockRegister(temp, position, position + 1, Primitive::kPrimInt);
+      BlockRegister(temp, position, position + 1);
     } else {
+      DCHECK(temp.IsUnallocated());
       LiveInterval* interval = LiveInterval::MakeTempInterval(allocator_, Primitive::kPrimInt);
       temp_intervals_.Add(interval);
       interval->AddRange(position, position + 1);
@@ -160,10 +190,6 @@
   bool core_register = (instruction->GetType() != Primitive::kPrimDouble)
       && (instruction->GetType() != Primitive::kPrimFloat);
 
-  GrowableArray<LiveInterval*>& unhandled = core_register
-      ? unhandled_core_intervals_
-      : unhandled_fp_intervals_;
-
   if (locations->CanCall()) {
     if (!instruction->IsSuspendCheck()) {
       codegen_->MarkNotLeaf();
@@ -180,7 +206,8 @@
       // maximum before updating locations.
       LiveInterval* interval = LiveInterval::MakeSlowPathInterval(allocator_, instruction);
       interval->AddRange(position, position + 1);
-      unhandled.Add(interval);
+      unhandled_core_intervals_.Add(interval);
+      unhandled_fp_intervals_.Add(interval);
     }
   }
 
@@ -189,21 +216,29 @@
     for (size_t i = 0; i < codegen_->GetNumberOfCoreRegisters(); ++i) {
       BlockRegister(Location::RegisterLocation(i),
                     position,
-                    position + 1,
-                    Primitive::kPrimInt);
+                    position + 1);
+    }
+    for (size_t i = 0; i < codegen_->GetNumberOfFloatingPointRegisters(); ++i) {
+      BlockRegister(Location::FpuRegisterLocation(i),
+                    position,
+                    position + 1);
     }
   }
 
   for (size_t i = 0; i < instruction->InputCount(); ++i) {
     Location input = locations->InAt(i);
-    if (input.IsRegister()) {
-      BlockRegister(input, position, position + 1, instruction->InputAt(i)->GetType());
+    if (input.IsRegister() || input.IsFpuRegister()) {
+      BlockRegister(input, position, position + 1);
     }
   }
 
   LiveInterval* current = instruction->GetLiveInterval();
   if (current == nullptr) return;
 
+  GrowableArray<LiveInterval*>& unhandled = core_register
+      ? unhandled_core_intervals_
+      : unhandled_fp_intervals_;
+
   DCHECK(unhandled.IsEmpty() || current->StartsBeforeOrAt(unhandled.Peek()));
   // Some instructions define their output in fixed register/stack slot. We need
   // to ensure we know these locations before doing register allocation. For a
@@ -213,21 +248,24 @@
   //
   // The backwards walking ensures the ranges are ordered on increasing start positions.
   Location output = locations->Out();
-  if (output.IsRegister()) {
+  if (output.IsRegister() || output.IsFpuRegister()) {
     // Shift the interval's start by one to account for the blocked register.
     current->SetFrom(position + 1);
     current->SetRegister(output.reg());
-    BlockRegister(output, position, position + 1, instruction->GetType());
+    BlockRegister(output, position, position + 1);
+  } else if (!locations->OutputOverlapsWithInputs()) {
+    // Shift the interval's start by one to not interfere with the inputs.
+    current->SetFrom(position + 1);
   } else if (output.IsStackSlot() || output.IsDoubleStackSlot()) {
     current->SetSpillSlot(output.GetStackIndex());
   }
 
   // If needed, add interval to the list of unhandled intervals.
   if (current->HasSpillSlot() || instruction->IsConstant()) {
-    // Split before first register use.
+    // Split just before first register use.
     size_t first_register_use = current->FirstRegisterUse();
     if (first_register_use != kNoLifetime) {
-      LiveInterval* split = Split(current, first_register_use);
+      LiveInterval* split = Split(current, first_register_use - 1);
       // Don't add direclty to `unhandled`, it needs to be sorted and the start
       // of this new interval might be after intervals already in the list.
       AddSorted(&unhandled, split);
@@ -278,10 +316,19 @@
     }
   }
 
-  for (size_t i = 0, e = physical_register_intervals_.Size(); i < e; ++i) {
-    LiveInterval* fixed = physical_register_intervals_.Get(i);
-    if (fixed != nullptr && ShouldProcess(processing_core_registers_, fixed)) {
-      intervals.Add(fixed);
+  if (processing_core_registers_) {
+    for (size_t i = 0, e = physical_core_register_intervals_.Size(); i < e; ++i) {
+      LiveInterval* fixed = physical_core_register_intervals_.Get(i);
+      if (fixed != nullptr) {
+        intervals.Add(fixed);
+      }
+    }
+  } else {
+    for (size_t i = 0, e = physical_fp_register_intervals_.Size(); i < e; ++i) {
+      LiveInterval* fixed = physical_fp_register_intervals_.Get(i);
+      if (fixed != nullptr) {
+        intervals.Add(fixed);
+      }
     }
   }
 
@@ -374,10 +421,10 @@
   interval->Dump(stream);
   stream << ": ";
   if (interval->HasRegister()) {
-    if (processing_core_registers_) {
-      codegen_->DumpCoreRegister(stream, interval->GetRegister());
-    } else {
+    if (interval->IsFloatingPoint()) {
       codegen_->DumpFloatingPointRegister(stream, interval->GetRegister());
+    } else {
+      codegen_->DumpCoreRegister(stream, interval->GetRegister());
     }
   } else {
     stream << "spilled";
@@ -391,6 +438,7 @@
     // (1) Remove interval with the lowest start position from unhandled.
     LiveInterval* current = unhandled_->Pop();
     DCHECK(!current->IsFixed() && !current->HasSpillSlot());
+    DCHECK(unhandled_->IsEmpty() || unhandled_->Peek()->GetStart() >= current->GetStart());
     size_t position = current->GetStart();
 
     // (2) Remove currently active intervals that are dead at this position.
@@ -519,10 +567,9 @@
 }
 
 bool RegisterAllocator::IsBlocked(int reg) const {
-  // TODO: This only works for core registers and needs to be adjusted for
-  // floating point registers.
-  DCHECK(processing_core_registers_);
-  return blocked_registers_[reg];
+  return processing_core_registers_
+      ? blocked_core_registers_[reg]
+      : blocked_fp_registers_[reg];
 }
 
 // Find the register that is used the last, and spill the interval
@@ -591,7 +638,9 @@
     // If the first use of that instruction is after the last use of the found
     // register, we split this interval just before its first register use.
     AllocateSpillSlotFor(current);
-    LiveInterval* split = Split(current, first_register_use);
+    LiveInterval* split = Split(current, first_register_use - 1);
+    DCHECK_NE(current, split) << "There is not enough registers available for "
+      << split->GetParent()->GetDefinedBy()->DebugName();
     AddSorted(unhandled_, split);
     return false;
   } else {
@@ -635,6 +684,7 @@
 }
 
 void RegisterAllocator::AddSorted(GrowableArray<LiveInterval*>* array, LiveInterval* interval) {
+  DCHECK(!interval->IsFixed() && !interval->HasSpillSlot());
   size_t insert_at = 0;
   for (size_t i = array->Size(); i > 0; --i) {
     LiveInterval* current = array->Get(i - 1);
@@ -723,17 +773,11 @@
   parent->SetSpillSlot((slot + reserved_out_slots_) * kVRegSize);
 }
 
-// We create a special marker for inputs moves to differentiate them from
-// moves created during resolution. They must be different instructions
-// because the input moves work on the assumption that the interval moves
-// have been executed.
-static constexpr size_t kInputMoveLifetimePosition = 0;
-static bool IsInputMove(HInstruction* instruction) {
-  return instruction->GetLifetimePosition() == kInputMoveLifetimePosition;
-}
-
 static bool IsValidDestination(Location destination) {
-  return destination.IsRegister() || destination.IsStackSlot() || destination.IsDoubleStackSlot();
+  return destination.IsRegister()
+      || destination.IsFpuRegister()
+      || destination.IsStackSlot()
+      || destination.IsDoubleStackSlot();
 }
 
 void RegisterAllocator::AddInputMoveFor(HInstruction* user,
@@ -742,20 +786,20 @@
   DCHECK(IsValidDestination(destination));
   if (source.Equals(destination)) return;
 
-  DCHECK(user->AsPhi() == nullptr);
+  DCHECK(!user->IsPhi());
 
   HInstruction* previous = user->GetPrevious();
   HParallelMove* move = nullptr;
   if (previous == nullptr
-      || previous->AsParallelMove() == nullptr
-      || !IsInputMove(previous)) {
+      || !previous->IsParallelMove()
+      || previous->GetLifetimePosition() < user->GetLifetimePosition()) {
     move = new (allocator_) HParallelMove(allocator_);
-    move->SetLifetimePosition(kInputMoveLifetimePosition);
+    move->SetLifetimePosition(user->GetLifetimePosition());
     user->GetBlock()->InsertInstructionBefore(move, user);
   } else {
     move = previous->AsParallelMove();
   }
-  DCHECK(IsInputMove(move));
+  DCHECK_EQ(move->GetLifetimePosition(), user->GetLifetimePosition());
   move->AddMove(new (allocator_) MoveOperands(source, destination, nullptr));
 }
 
@@ -778,7 +822,7 @@
     move = at->GetNext()->AsParallelMove();
     // This is a parallel move for connecting siblings in a same block. We need to
     // differentiate it with moves for connecting blocks, and input moves.
-    if (move == nullptr || IsInputMove(move) || move->GetLifetimePosition() > position) {
+    if (move == nullptr || move->GetLifetimePosition() > position) {
       move = new (allocator_) HParallelMove(allocator_);
       move->SetLifetimePosition(position);
       at->GetBlock()->InsertInstructionBefore(move, at->GetNext());
@@ -786,12 +830,6 @@
   } else {
     // Move must happen before the instruction.
     HInstruction* previous = at->GetPrevious();
-    if (previous != nullptr && previous->IsParallelMove() && IsInputMove(previous)) {
-      // This is a parallel move for connecting siblings in a same block. We need to
-      // differentiate it with input moves.
-      at = previous;
-      previous = previous->GetPrevious();
-    }
     if (previous == nullptr
         || !previous->IsParallelMove()
         || previous->GetLifetimePosition() != position) {
@@ -866,7 +904,7 @@
   DCHECK(IsValidDestination(destination));
   if (source.Equals(destination)) return;
 
-  if (instruction->AsPhi() != nullptr) {
+  if (instruction->IsPhi()) {
     InsertParallelMoveAtEntryOf(instruction->GetBlock(), instruction, source, destination);
     return;
   }
@@ -889,7 +927,9 @@
   if (current->HasSpillSlot() && current->HasRegister()) {
     // We spill eagerly, so move must be at definition.
     InsertMoveAfter(interval->GetDefinedBy(),
-                    Location::RegisterLocation(interval->GetRegister()),
+                    interval->IsFloatingPoint()
+                        ? Location::FpuRegisterLocation(interval->GetRegister())
+                        : Location::RegisterLocation(interval->GetRegister()),
                     interval->NeedsTwoSpillSlots()
                         ? Location::DoubleStackSlot(interval->GetParent()->GetSpillSlot())
                         : Location::StackSlot(interval->GetParent()->GetSpillSlot()));
@@ -947,6 +987,10 @@
           }
           break;
         }
+        case Location::kFpuRegister: {
+          locations->AddLiveRegister(source);
+          break;
+        }
         case Location::kStackSlot:  // Fall-through
         case Location::kDoubleStackSlot:  // Fall-through
         case Location::kConstant: {
@@ -1036,7 +1080,7 @@
     LiveInterval* current = instruction->GetLiveInterval();
     LocationSummary* locations = instruction->GetLocations();
     Location location = locations->Out();
-    if (instruction->AsParameterValue() != nullptr) {
+    if (instruction->IsParameterValue()) {
       // Now that we know the frame size, adjust the parameter's location.
       if (location.IsStackSlot()) {
         location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
@@ -1110,6 +1154,7 @@
       current = at;
     }
     LocationSummary* locations = at->GetLocations();
+    DCHECK(temp->GetType() == Primitive::kPrimInt);
     locations->SetTempAt(
         temp_index++, Location::RegisterLocation(temp->GetRegister()));
   }
diff --git a/compiler/optimizing/register_allocator.h b/compiler/optimizing/register_allocator.h
index d4c233a..b881539 100644
--- a/compiler/optimizing/register_allocator.h
+++ b/compiler/optimizing/register_allocator.h
@@ -21,8 +21,6 @@
 #include "primitive.h"
 #include "utils/growable_array.h"
 
-#include "gtest/gtest.h"
-
 namespace art {
 
 class CodeGenerator;
@@ -96,7 +94,7 @@
   bool IsBlocked(int reg) const;
 
   // Update the interval for the register in `location` to cover [start, end).
-  void BlockRegister(Location location, size_t start, size_t end, Primitive::Type type);
+  void BlockRegister(Location location, size_t start, size_t end);
 
   // Allocate a spill slot for the given interval.
   void AllocateSpillSlotFor(LiveInterval* interval);
@@ -158,7 +156,8 @@
 
   // Fixed intervals for physical registers. Such intervals cover the positions
   // where an instruction requires a specific register.
-  GrowableArray<LiveInterval*> physical_register_intervals_;
+  GrowableArray<LiveInterval*> physical_core_register_intervals_;
+  GrowableArray<LiveInterval*> physical_fp_register_intervals_;
 
   // Intervals for temporaries. Such intervals cover the positions
   // where an instruction requires a temporary.
@@ -181,7 +180,8 @@
   size_t* registers_array_;
 
   // Blocked registers, as decided by the code generator.
-  bool* const blocked_registers_;
+  bool* const blocked_core_registers_;
+  bool* const blocked_fp_registers_;
 
   // Slots reserved for out arguments.
   size_t reserved_out_slots_;
@@ -189,7 +189,7 @@
   // The maximum live registers at safepoints.
   size_t maximum_number_of_live_registers_;
 
-  FRIEND_TEST(RegisterAllocatorTest, FreeUntil);
+  ART_FRIEND_TEST(RegisterAllocatorTest, FreeUntil);
 
   DISALLOW_COPY_AND_ASSIGN(RegisterAllocator);
 };
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index 7517a6b..2d84a9d 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -348,14 +348,14 @@
   // Split at the next instruction.
   interval = interval->SplitAt(first_add->GetLifetimePosition() + 2);
   // The user of the split is the last add.
-  ASSERT_EQ(interval->FirstRegisterUse(), last_add->GetLifetimePosition() - 1);
+  ASSERT_EQ(interval->FirstRegisterUse(), last_add->GetLifetimePosition());
 
   // Split before the last add.
   LiveInterval* new_interval = interval->SplitAt(last_add->GetLifetimePosition() - 1);
   // Ensure the current interval has no register use...
   ASSERT_EQ(interval->FirstRegisterUse(), kNoLifetime);
   // And the new interval has it for the last add.
-  ASSERT_EQ(new_interval->FirstRegisterUse(), last_add->GetLifetimePosition() - 1);
+  ASSERT_EQ(new_interval->FirstRegisterUse(), last_add->GetLifetimePosition());
 }
 
 TEST(RegisterAllocatorTest, DeadPhi) {
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index 471307e..a0cc8a9 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -51,7 +51,7 @@
        !it.Done();
        it.Advance()) {
     HInstruction* current = it.Current();
-    if (current->AsLocal() != nullptr) {
+    if (current->IsLocal()) {
       current->GetBlock()->RemoveInstruction(current);
     }
   }
@@ -129,8 +129,112 @@
   }
 }
 
+/**
+ * Constants in the Dex format are not typed. So the builder types them as
+ * integers, but when doing the SSA form, we might realize the constant
+ * is used for floating point operations. We create a floating-point equivalent
+ * constant to make the operations correctly typed.
+ */
+static HFloatConstant* GetFloatEquivalent(HIntConstant* constant) {
+  // We place the floating point constant next to this constant.
+  HFloatConstant* result = constant->GetNext()->AsFloatConstant();
+  if (result == nullptr) {
+    HGraph* graph = constant->GetBlock()->GetGraph();
+    ArenaAllocator* allocator = graph->GetArena();
+    result = new (allocator) HFloatConstant(bit_cast<int32_t, float>(constant->GetValue()));
+    constant->GetBlock()->InsertInstructionBefore(result, constant->GetNext());
+  } else {
+    // If there is already a constant with the expected type, we know it is
+    // the floating point equivalent of this constant.
+    DCHECK_EQ((bit_cast<float, int32_t>(result->GetValue())), constant->GetValue());
+  }
+  return result;
+}
+
+/**
+ * Wide constants in the Dex format are not typed. So the builder types them as
+ * longs, but when doing the SSA form, we might realize the constant
+ * is used for floating point operations. We create a floating-point equivalent
+ * constant to make the operations correctly typed.
+ */
+static HDoubleConstant* GetDoubleEquivalent(HLongConstant* constant) {
+  // We place the floating point constant next to this constant.
+  HDoubleConstant* result = constant->GetNext()->AsDoubleConstant();
+  if (result == nullptr) {
+    HGraph* graph = constant->GetBlock()->GetGraph();
+    ArenaAllocator* allocator = graph->GetArena();
+    result = new (allocator) HDoubleConstant(bit_cast<int64_t, double>(constant->GetValue()));
+    constant->GetBlock()->InsertInstructionBefore(result, constant->GetNext());
+  } else {
+    // If there is already a constant with the expected type, we know it is
+    // the floating point equivalent of this constant.
+    DCHECK_EQ((bit_cast<double, int64_t>(result->GetValue())), constant->GetValue());
+  }
+  return result;
+}
+
+/**
+ * Because of Dex format, we might end up having the same phi being
+ * used for non floating point operations and floating point operations. Because
+ * we want the graph to be correctly typed (and thereafter avoid moves between
+ * floating point registers and core registers), we need to create a copy of the
+ * phi with a floating point type.
+ */
+static HPhi* GetFloatOrDoubleEquivalentOfPhi(HPhi* phi, Primitive::Type type) {
+  // We place the floating point phi next to this phi.
+  HInstruction* next = phi->GetNext();
+  if (next == nullptr
+      || (next->GetType() != Primitive::kPrimDouble && next->GetType() != Primitive::kPrimFloat)) {
+    ArenaAllocator* allocator = phi->GetBlock()->GetGraph()->GetArena();
+    HPhi* new_phi = new (allocator) HPhi(allocator, phi->GetRegNumber(), phi->InputCount(), type);
+    for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
+      // Copy the inputs. Note that the graph may not be correctly typed by doing this copy,
+      // but the type propagation phase will fix it.
+      new_phi->SetRawInputAt(i, phi->InputAt(i));
+    }
+    phi->GetBlock()->InsertPhiAfter(new_phi, phi);
+    return new_phi;
+  } else {
+    // If there is already a phi with the expected type, we know it is the floating
+    // point equivalent of this phi.
+    DCHECK_EQ(next->AsPhi()->GetRegNumber(), phi->GetRegNumber());
+    return next->AsPhi();
+  }
+}
+
+HInstruction* SsaBuilder::GetFloatOrDoubleEquivalent(HInstruction* user,
+                                                     HInstruction* value,
+                                                     Primitive::Type type) {
+  if (value->IsArrayGet()) {
+    // The verifier has checked that values in arrays cannot be used for both
+    // floating point and non-floating point operations. It is therefore safe to just
+    // change the type of the operation.
+    value->AsArrayGet()->SetType(type);
+    return value;
+  } else if (value->IsLongConstant()) {
+    return GetDoubleEquivalent(value->AsLongConstant());
+  } else if (value->IsIntConstant()) {
+    return GetFloatEquivalent(value->AsIntConstant());
+  } else if (value->IsPhi()) {
+    return GetFloatOrDoubleEquivalentOfPhi(value->AsPhi(), type);
+  } else {
+    // For other instructions, we assume the verifier has checked that the dex format is correctly
+    // typed and the value in a dex register will not be used for both floating point and
+    // non-floating point operations. So the only reason an instruction would want a floating
+    // point equivalent is for an unused phi that will be removed by the dead phi elimination phase.
+    DCHECK(user->IsPhi());
+    return value;
+  }
+}
+
 void SsaBuilder::VisitLoadLocal(HLoadLocal* load) {
-  load->ReplaceWith(current_locals_->Get(load->GetLocal()->GetRegNumber()));
+  HInstruction* value = current_locals_->Get(load->GetLocal()->GetRegNumber());
+  if (load->GetType() != value->GetType()
+      && (load->GetType() == Primitive::kPrimFloat || load->GetType() == Primitive::kPrimDouble)) {
+    // If the operation requests a specific type, we make sure its input is of that type.
+    value = GetFloatOrDoubleEquivalent(load, value, load->GetType());
+  }
+  load->ReplaceWith(value);
   load->GetBlock()->RemoveInstruction(load);
 }
 
diff --git a/compiler/optimizing/ssa_builder.h b/compiler/optimizing/ssa_builder.h
index 9d8c072..24f5ac5 100644
--- a/compiler/optimizing/ssa_builder.h
+++ b/compiler/optimizing/ssa_builder.h
@@ -52,6 +52,10 @@
   void VisitStoreLocal(HStoreLocal* store);
   void VisitInstruction(HInstruction* instruction);
 
+  static HInstruction* GetFloatOrDoubleEquivalent(HInstruction* user,
+                                                  HInstruction* instruction,
+                                                  Primitive::Type type);
+
  private:
   // Locals for the current block being visited.
   GrowableArray<HInstruction*>* current_locals_;
diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc
index f0edc64..1e34670 100644
--- a/compiler/optimizing/ssa_liveness_analysis.cc
+++ b/compiler/optimizing/ssa_liveness_analysis.cc
@@ -319,7 +319,7 @@
       if (user->IsPhi()) {
         // If the phi has a register, try to use the same.
         Location phi_location = user->GetLiveInterval()->ToLocation();
-        if (phi_location.IsRegister() && free_until[phi_location.reg()] >= use_position) {
+        if (SameRegisterKind(phi_location) && free_until[phi_location.reg()] >= use_position) {
           return phi_location.reg();
         }
         const GrowableArray<HBasicBlock*>& predecessors = user->GetBlock()->GetPredecessors();
@@ -345,7 +345,7 @@
         // We use the user's lifetime position - 1 (and not `use_position`) because the
         // register is blocked at the beginning of the user.
         size_t position = user->GetLifetimePosition() - 1;
-        if (expected.IsRegister() && free_until[expected.reg()] >= position) {
+        if (SameRegisterKind(expected) && free_until[expected.reg()] >= position) {
           return expected.reg();
         }
       }
@@ -368,7 +368,7 @@
         // If the input dies at the end of the predecessor, we know its register can
         // be reused.
         Location input_location = input_interval.ToLocation();
-        if (input_location.IsRegister()) {
+        if (SameRegisterKind(input_location)) {
           return input_location.reg();
         }
       }
@@ -384,7 +384,7 @@
         // If the input dies at the start of this instruction, we know its register can
         // be reused.
         Location location = input_interval.ToLocation();
-        if (location.IsRegister()) {
+        if (SameRegisterKind(location)) {
           return location.reg();
         }
       }
@@ -393,13 +393,21 @@
   return kNoRegister;
 }
 
+bool LiveInterval::SameRegisterKind(Location other) const {
+  return IsFloatingPoint()
+      ? other.IsFpuRegister()
+      : other.IsRegister();
+}
+
 bool LiveInterval::NeedsTwoSpillSlots() const {
   return type_ == Primitive::kPrimLong || type_ == Primitive::kPrimDouble;
 }
 
 Location LiveInterval::ToLocation() const {
   if (HasRegister()) {
-    return Location::RegisterLocation(GetRegister());
+    return IsFloatingPoint()
+        ? Location::FpuRegisterLocation(GetRegister())
+        : Location::RegisterLocation(GetRegister());
   } else {
     HInstruction* defined_by = GetParent()->GetDefinedBy();
     if (defined_by->IsConstant()) {
diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h
index e9bd303..7dda4f6 100644
--- a/compiler/optimizing/ssa_liveness_analysis.h
+++ b/compiler/optimizing/ssa_liveness_analysis.h
@@ -32,6 +32,7 @@
         live_in_(allocator, number_of_ssa_values, false),
         live_out_(allocator, number_of_ssa_values, false),
         kill_(allocator, number_of_ssa_values, false) {
+    UNUSED(block_);
     live_in_.ClearAllBits();
     live_out_.ClearAllBits();
     kill_.ClearAllBits();
@@ -188,10 +189,14 @@
         && (first_use_->GetPosition() < position)) {
       // The user uses the instruction multiple times, and one use dies before the other.
       // We update the use list so that the latter is first.
+      UsePosition* cursor = first_use_;
+      while ((cursor->GetNext() != nullptr) && (cursor->GetNext()->GetPosition() < position)) {
+        cursor = cursor->GetNext();
+      }
       DCHECK(first_use_->GetPosition() + 1 == position);
       UsePosition* new_use = new (allocator_) UsePosition(
-          instruction, input_index, is_environment, position, first_use_->GetNext());
-      first_use_->SetNext(new_use);
+          instruction, input_index, is_environment, position, cursor->GetNext());
+      cursor->SetNext(new_use);
       if (first_range_->GetEnd() == first_use_->GetPosition()) {
         first_range_->end_ = position;
       }
@@ -354,6 +359,10 @@
              || (location.GetPolicy() == Location::kSameAsFirstInput
                  && locations->InAt(0).GetPolicy() == Location::kRequiresRegister)) {
           return position;
+        } else if ((location.GetPolicy() == Location::kRequiresFpuRegister)
+                   || (location.GetPolicy() == Location::kSameAsFirstInput
+                       && locations->InAt(0).GetPolicy() == Location::kRequiresFpuRegister)) {
+          return position;
         }
       }
     }
@@ -362,12 +371,12 @@
     size_t end = GetEnd();
     while (use != nullptr && use->GetPosition() <= end) {
       size_t use_position = use->GetPosition();
-      if (use_position >= position && !use->GetIsEnvironment()) {
+      if (use_position > position && !use->GetIsEnvironment()) {
         Location location = use->GetUser()->GetLocations()->InAt(use->GetInputIndex());
-        if (location.IsUnallocated() && location.GetPolicy() == Location::kRequiresRegister) {
-          // Return the lifetime just before the user, so that the interval has a register
-          // when entering the user.
-          return use->GetUser()->GetLifetimePosition() - 1;
+        if (location.IsUnallocated()
+            && (location.GetPolicy() == Location::kRequiresRegister
+                || location.GetPolicy() == Location::kRequiresFpuRegister)) {
+          return use_position;
         }
       }
       use = use->GetNext();
@@ -498,6 +507,10 @@
   // slots for spilling.
   bool NeedsTwoSpillSlots() const;
 
+  bool IsFloatingPoint() const {
+    return type_ == Primitive::kPrimFloat || type_ == Primitive::kPrimDouble;
+  }
+
   // Converts the location of the interval to a `Location` object.
   Location ToLocation() const;
 
@@ -509,6 +522,9 @@
 
   bool IsTemp() const { return is_temp_; }
 
+  // Returns whether `other` and `this` share the same kind of register.
+  bool SameRegisterKind(Location other) const;
+
  private:
   ArenaAllocator* const allocator_;
 
diff --git a/compiler/optimizing/ssa_phi_elimination.cc b/compiler/optimizing/ssa_phi_elimination.cc
index e02a182..4eda0f3 100644
--- a/compiler/optimizing/ssa_phi_elimination.cc
+++ b/compiler/optimizing/ssa_phi_elimination.cc
@@ -24,18 +24,13 @@
     HBasicBlock* block = it.Current();
     for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
       HPhi* phi = it.Current()->AsPhi();
-      if (phi->HasEnvironmentUses()) {
-        // TODO: Do we want to keep that phi alive?
-        worklist_.Add(phi);
-        phi->SetLive();
-        continue;
-      }
       for (HUseIterator<HInstruction> it(phi->GetUses()); !it.Done(); it.Advance()) {
         HUseListNode<HInstruction>* current = it.Current();
         HInstruction* user = current->GetUser();
         if (!user->IsPhi()) {
           worklist_.Add(phi);
           phi->SetLive();
+          break;
         } else {
           phi->SetDead();
         }
@@ -76,6 +71,14 @@
             current->RemoveUser(user, user_node->GetIndex());
           }
         }
+        if (current->HasEnvironmentUses()) {
+          for (HUseIterator<HEnvironment> it(current->GetEnvUses()); !it.Done(); it.Advance()) {
+            HUseListNode<HEnvironment>* user_node = it.Current();
+            HEnvironment* user = user_node->GetUser();
+            user->SetRawEnvAt(user_node->GetIndex(), nullptr);
+            current->RemoveEnvironmentUser(user, user_node->GetIndex());
+          }
+        }
         block->RemovePhi(current->AsPhi());
       }
       current = next;
diff --git a/compiler/optimizing/ssa_type_propagation.cc b/compiler/optimizing/ssa_type_propagation.cc
index a860cb7..3828142 100644
--- a/compiler/optimizing/ssa_type_propagation.cc
+++ b/compiler/optimizing/ssa_type_propagation.cc
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "ssa_builder.h"
 #include "ssa_type_propagation.h"
 
 #include "nodes.h"
@@ -38,15 +39,31 @@
 
 // Re-compute and update the type of the instruction. Returns
 // whether or not the type was changed.
-static bool UpdateType(HPhi* phi) {
+bool SsaTypePropagation::UpdateType(HPhi* phi) {
   Primitive::Type existing = phi->GetType();
 
-  Primitive::Type new_type = Primitive::kPrimVoid;
+  Primitive::Type new_type = existing;
   for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
     Primitive::Type input_type = phi->InputAt(i)->GetType();
     new_type = MergeTypes(new_type, input_type);
   }
   phi->SetType(new_type);
+
+  if (new_type == Primitive::kPrimDouble || new_type == Primitive::kPrimFloat) {
+    // If the phi is of floating point type, we need to update its inputs to that
+    // type. For inputs that are phis, we need to recompute their types.
+    for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
+      HInstruction* input = phi->InputAt(i);
+      if (input->GetType() != new_type) {
+        HInstruction* equivalent = SsaBuilder::GetFloatOrDoubleEquivalent(phi, input, new_type);
+        phi->ReplaceInput(equivalent, i);
+        if (equivalent->IsPhi()) {
+          AddToWorklist(equivalent->AsPhi());
+        }
+      }
+    }
+  }
+
   return existing != new_type;
 }
 
@@ -63,7 +80,12 @@
       HPhi* phi = it.Current()->AsPhi();
       // Set the initial type for the phi. Use the non back edge input for reaching
       // a fixed point faster.
-      phi->SetType(phi->InputAt(0)->GetType());
+      Primitive::Type phi_type = phi->GetType();
+      // We merge with the existing type, that has been set by the SSA builder.
+      DCHECK(phi_type == Primitive::kPrimVoid
+          || phi_type == Primitive::kPrimFloat
+          || phi_type == Primitive::kPrimDouble);
+      phi->SetType(MergeTypes(phi->InputAt(0)->GetType(), phi->GetType()));
       AddToWorklist(phi);
     }
   } else {
diff --git a/compiler/optimizing/ssa_type_propagation.h b/compiler/optimizing/ssa_type_propagation.h
index 5f471a9..f4d3d63 100644
--- a/compiler/optimizing/ssa_type_propagation.h
+++ b/compiler/optimizing/ssa_type_propagation.h
@@ -34,6 +34,7 @@
   void ProcessWorklist();
   void AddToWorklist(HPhi* phi);
   void AddDependentInstructionsToWorklist(HPhi* phi);
+  bool UpdateType(HPhi* phi);
 
   HGraph* const graph_;
   GrowableArray<HPhi*> worklist_;
diff --git a/compiler/trampolines/trampoline_compiler.cc b/compiler/trampolines/trampoline_compiler.cc
index 6da375a..733b58f 100644
--- a/compiler/trampolines/trampoline_compiler.cc
+++ b/compiler/trampolines/trampoline_compiler.cc
@@ -62,23 +62,23 @@
 
   switch (abi) {
     case kInterpreterAbi:  // Thread* is first argument (X0) in interpreter ABI.
-      __ JumpTo(Arm64ManagedRegister::FromCoreRegister(X0), Offset(offset.Int32Value()),
-          Arm64ManagedRegister::FromCoreRegister(IP1));
+      __ JumpTo(Arm64ManagedRegister::FromXRegister(X0), Offset(offset.Int32Value()),
+          Arm64ManagedRegister::FromXRegister(IP1));
 
       break;
     case kJniAbi:  // Load via Thread* held in JNIEnv* in first argument (X0).
-      __ LoadRawPtr(Arm64ManagedRegister::FromCoreRegister(IP1),
-                      Arm64ManagedRegister::FromCoreRegister(X0),
+      __ LoadRawPtr(Arm64ManagedRegister::FromXRegister(IP1),
+                      Arm64ManagedRegister::FromXRegister(X0),
                       Offset(JNIEnvExt::SelfOffset().Int32Value()));
 
-      __ JumpTo(Arm64ManagedRegister::FromCoreRegister(IP1), Offset(offset.Int32Value()),
-                Arm64ManagedRegister::FromCoreRegister(IP0));
+      __ JumpTo(Arm64ManagedRegister::FromXRegister(IP1), Offset(offset.Int32Value()),
+                Arm64ManagedRegister::FromXRegister(IP0));
 
       break;
     case kPortableAbi:  // X18 holds Thread*.
     case kQuickAbi:  // Fall-through.
-      __ JumpTo(Arm64ManagedRegister::FromCoreRegister(TR), Offset(offset.Int32Value()),
-                Arm64ManagedRegister::FromCoreRegister(IP0));
+      __ JumpTo(Arm64ManagedRegister::FromXRegister(TR), Offset(offset.Int32Value()),
+                Arm64ManagedRegister::FromXRegister(IP0));
 
       break;
   }
@@ -166,7 +166,7 @@
       return x86_64::CreateTrampoline(offset);
     default:
       LOG(FATAL) << "Unexpected InstructionSet: " << isa;
-      return nullptr;
+      UNREACHABLE();
   }
 }
 
@@ -182,7 +182,7 @@
       return x86::CreateTrampoline(offset);
     default:
       LOG(FATAL) << "Unexpected InstructionSet: " << isa;
-      return nullptr;
+      UNREACHABLE();
   }
 }
 
diff --git a/compiler/utils/arena_allocator.cc b/compiler/utils/arena_allocator.cc
index 516ac2b..0c93f0a 100644
--- a/compiler/utils/arena_allocator.cc
+++ b/compiler/utils/arena_allocator.cc
@@ -15,6 +15,7 @@
  */
 
 #include <algorithm>
+#include <iomanip>
 #include <numeric>
 
 #include "arena_allocator.h"
diff --git a/compiler/utils/arm64/assembler_arm64.cc b/compiler/utils/arm64/assembler_arm64.cc
index 25e02c3..1af7374 100644
--- a/compiler/utils/arm64/assembler_arm64.cc
+++ b/compiler/utils/arm64/assembler_arm64.cc
@@ -52,7 +52,7 @@
 }
 
 void Arm64Assembler::GetCurrentThread(ManagedRegister tr) {
-  ___ Mov(reg_x(tr.AsArm64().AsCoreRegister()), reg_x(ETR));
+  ___ Mov(reg_x(tr.AsArm64().AsXRegister()), reg_x(ETR));
 }
 
 void Arm64Assembler::GetCurrentThread(FrameOffset offset, ManagedRegister /* scratch */) {
@@ -71,11 +71,11 @@
   AddConstant(SP, adjust);
 }
 
-void Arm64Assembler::AddConstant(Register rd, int32_t value, Condition cond) {
+void Arm64Assembler::AddConstant(XRegister rd, int32_t value, Condition cond) {
   AddConstant(rd, rd, value, cond);
 }
 
-void Arm64Assembler::AddConstant(Register rd, Register rn, int32_t value,
+void Arm64Assembler::AddConstant(XRegister rd, XRegister rn, int32_t value,
                                  Condition cond) {
   if ((cond == al) || (cond == nv)) {
     // VIXL macro-assembler handles all variants.
@@ -92,7 +92,7 @@
 }
 
 void Arm64Assembler::StoreWToOffset(StoreOperandType type, WRegister source,
-                                    Register base, int32_t offset) {
+                                    XRegister base, int32_t offset) {
   switch (type) {
     case kStoreByte:
       ___ Strb(reg_w(source), MEM_OP(reg_x(base), offset));
@@ -108,16 +108,16 @@
   }
 }
 
-void Arm64Assembler::StoreToOffset(Register source, Register base, int32_t offset) {
+void Arm64Assembler::StoreToOffset(XRegister source, XRegister base, int32_t offset) {
   CHECK_NE(source, SP);
   ___ Str(reg_x(source), MEM_OP(reg_x(base), offset));
 }
 
-void Arm64Assembler::StoreSToOffset(SRegister source, Register base, int32_t offset) {
+void Arm64Assembler::StoreSToOffset(SRegister source, XRegister base, int32_t offset) {
   ___ Str(reg_s(source), MEM_OP(reg_x(base), offset));
 }
 
-void Arm64Assembler::StoreDToOffset(DRegister source, Register base, int32_t offset) {
+void Arm64Assembler::StoreDToOffset(DRegister source, XRegister base, int32_t offset) {
   ___ Str(reg_d(source), MEM_OP(reg_x(base), offset));
 }
 
@@ -128,9 +128,9 @@
   } else if (src.IsWRegister()) {
     CHECK_EQ(4u, size);
     StoreWToOffset(kStoreWord, src.AsWRegister(), SP, offs.Int32Value());
-  } else if (src.IsCoreRegister()) {
+  } else if (src.IsXRegister()) {
     CHECK_EQ(8u, size);
-    StoreToOffset(src.AsCoreRegister(), SP, offs.Int32Value());
+    StoreToOffset(src.AsXRegister(), SP, offs.Int32Value());
   } else if (src.IsSRegister()) {
     StoreSToOffset(src.AsSRegister(), SP, offs.Int32Value());
   } else {
@@ -141,41 +141,41 @@
 
 void Arm64Assembler::StoreRef(FrameOffset offs, ManagedRegister m_src) {
   Arm64ManagedRegister src = m_src.AsArm64();
-  CHECK(src.IsCoreRegister()) << src;
-  StoreWToOffset(kStoreWord, src.AsOverlappingCoreRegisterLow(), SP,
+  CHECK(src.IsXRegister()) << src;
+  StoreWToOffset(kStoreWord, src.AsOverlappingWRegister(), SP,
                  offs.Int32Value());
 }
 
 void Arm64Assembler::StoreRawPtr(FrameOffset offs, ManagedRegister m_src) {
   Arm64ManagedRegister src = m_src.AsArm64();
-  CHECK(src.IsCoreRegister()) << src;
-  StoreToOffset(src.AsCoreRegister(), SP, offs.Int32Value());
+  CHECK(src.IsXRegister()) << src;
+  StoreToOffset(src.AsXRegister(), SP, offs.Int32Value());
 }
 
 void Arm64Assembler::StoreImmediateToFrame(FrameOffset offs, uint32_t imm,
                                            ManagedRegister m_scratch) {
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
-  CHECK(scratch.IsCoreRegister()) << scratch;
-  LoadImmediate(scratch.AsCoreRegister(), imm);
-  StoreWToOffset(kStoreWord, scratch.AsOverlappingCoreRegisterLow(), SP,
+  CHECK(scratch.IsXRegister()) << scratch;
+  LoadImmediate(scratch.AsXRegister(), imm);
+  StoreWToOffset(kStoreWord, scratch.AsOverlappingWRegister(), SP,
                  offs.Int32Value());
 }
 
 void Arm64Assembler::StoreImmediateToThread64(ThreadOffset<8> offs, uint32_t imm,
                                             ManagedRegister m_scratch) {
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
-  CHECK(scratch.IsCoreRegister()) << scratch;
-  LoadImmediate(scratch.AsCoreRegister(), imm);
-  StoreToOffset(scratch.AsCoreRegister(), ETR, offs.Int32Value());
+  CHECK(scratch.IsXRegister()) << scratch;
+  LoadImmediate(scratch.AsXRegister(), imm);
+  StoreToOffset(scratch.AsXRegister(), ETR, offs.Int32Value());
 }
 
 void Arm64Assembler::StoreStackOffsetToThread64(ThreadOffset<8> tr_offs,
                                               FrameOffset fr_offs,
                                               ManagedRegister m_scratch) {
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
-  CHECK(scratch.IsCoreRegister()) << scratch;
-  AddConstant(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
-  StoreToOffset(scratch.AsCoreRegister(), ETR, tr_offs.Int32Value());
+  CHECK(scratch.IsXRegister()) << scratch;
+  AddConstant(scratch.AsXRegister(), SP, fr_offs.Int32Value());
+  StoreToOffset(scratch.AsXRegister(), ETR, tr_offs.Int32Value());
 }
 
 void Arm64Assembler::StoreStackPointerToThread64(ThreadOffset<8> tr_offs) {
@@ -189,13 +189,13 @@
                                    FrameOffset in_off, ManagedRegister m_scratch) {
   Arm64ManagedRegister source = m_source.AsArm64();
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
-  StoreToOffset(source.AsCoreRegister(), SP, dest_off.Int32Value());
-  LoadFromOffset(scratch.AsCoreRegister(), SP, in_off.Int32Value());
-  StoreToOffset(scratch.AsCoreRegister(), SP, dest_off.Int32Value() + 8);
+  StoreToOffset(source.AsXRegister(), SP, dest_off.Int32Value());
+  LoadFromOffset(scratch.AsXRegister(), SP, in_off.Int32Value());
+  StoreToOffset(scratch.AsXRegister(), SP, dest_off.Int32Value() + 8);
 }
 
 // Load routines.
-void Arm64Assembler::LoadImmediate(Register dest, int32_t value,
+void Arm64Assembler::LoadImmediate(XRegister dest, int32_t value,
                                    Condition cond) {
   if ((cond == al) || (cond == nv)) {
     ___ Mov(reg_x(dest), value);
@@ -215,7 +215,7 @@
 }
 
 void Arm64Assembler::LoadWFromOffset(LoadOperandType type, WRegister dest,
-                                     Register base, int32_t offset) {
+                                     XRegister base, int32_t offset) {
   switch (type) {
     case kLoadSignedByte:
       ___ Ldrsb(reg_w(dest), MEM_OP(reg_x(base), offset));
@@ -239,36 +239,36 @@
 
 // Note: We can extend this member by adding load type info - see
 // sign extended A64 load variants.
-void Arm64Assembler::LoadFromOffset(Register dest, Register base,
+void Arm64Assembler::LoadFromOffset(XRegister dest, XRegister base,
                                     int32_t offset) {
   CHECK_NE(dest, SP);
   ___ Ldr(reg_x(dest), MEM_OP(reg_x(base), offset));
 }
 
-void Arm64Assembler::LoadSFromOffset(SRegister dest, Register base,
+void Arm64Assembler::LoadSFromOffset(SRegister dest, XRegister base,
                                      int32_t offset) {
   ___ Ldr(reg_s(dest), MEM_OP(reg_x(base), offset));
 }
 
-void Arm64Assembler::LoadDFromOffset(DRegister dest, Register base,
+void Arm64Assembler::LoadDFromOffset(DRegister dest, XRegister base,
                                      int32_t offset) {
   ___ Ldr(reg_d(dest), MEM_OP(reg_x(base), offset));
 }
 
-void Arm64Assembler::Load(Arm64ManagedRegister dest, Register base,
+void Arm64Assembler::Load(Arm64ManagedRegister dest, XRegister base,
                           int32_t offset, size_t size) {
   if (dest.IsNoRegister()) {
     CHECK_EQ(0u, size) << dest;
   } else if (dest.IsWRegister()) {
     CHECK_EQ(4u, size) << dest;
     ___ Ldr(reg_w(dest.AsWRegister()), MEM_OP(reg_x(base), offset));
-  } else if (dest.IsCoreRegister()) {
-    CHECK_NE(dest.AsCoreRegister(), SP) << dest;
+  } else if (dest.IsXRegister()) {
+    CHECK_NE(dest.AsXRegister(), SP) << dest;
     if (size == 4u) {
-      ___ Ldr(reg_w(dest.AsOverlappingCoreRegisterLow()), MEM_OP(reg_x(base), offset));
+      ___ Ldr(reg_w(dest.AsOverlappingWRegister()), MEM_OP(reg_x(base), offset));
     } else {
       CHECK_EQ(8u, size) << dest;
-      ___ Ldr(reg_x(dest.AsCoreRegister()), MEM_OP(reg_x(base), offset));
+      ___ Ldr(reg_x(dest.AsXRegister()), MEM_OP(reg_x(base), offset));
     }
   } else if (dest.IsSRegister()) {
     ___ Ldr(reg_s(dest.AsSRegister()), MEM_OP(reg_x(base), offset));
@@ -288,19 +288,19 @@
 
 void Arm64Assembler::LoadRef(ManagedRegister m_dst, FrameOffset offs) {
   Arm64ManagedRegister dst = m_dst.AsArm64();
-  CHECK(dst.IsCoreRegister()) << dst;
-  LoadWFromOffset(kLoadWord, dst.AsOverlappingCoreRegisterLow(), SP, offs.Int32Value());
+  CHECK(dst.IsXRegister()) << dst;
+  LoadWFromOffset(kLoadWord, dst.AsOverlappingWRegister(), SP, offs.Int32Value());
 }
 
 void Arm64Assembler::LoadRef(ManagedRegister m_dst, ManagedRegister m_base,
                              MemberOffset offs) {
   Arm64ManagedRegister dst = m_dst.AsArm64();
   Arm64ManagedRegister base = m_base.AsArm64();
-  CHECK(dst.IsCoreRegister() && base.IsCoreRegister());
-  LoadWFromOffset(kLoadWord, dst.AsOverlappingCoreRegisterLow(), base.AsCoreRegister(),
+  CHECK(dst.IsXRegister() && base.IsXRegister());
+  LoadWFromOffset(kLoadWord, dst.AsOverlappingWRegister(), base.AsXRegister(),
                   offs.Int32Value());
   if (kPoisonHeapReferences) {
-    WRegister ref_reg = dst.AsOverlappingCoreRegisterLow();
+    WRegister ref_reg = dst.AsOverlappingWRegister();
     ___ Neg(reg_w(ref_reg), vixl::Operand(reg_w(ref_reg)));
   }
 }
@@ -308,17 +308,17 @@
 void Arm64Assembler::LoadRawPtr(ManagedRegister m_dst, ManagedRegister m_base, Offset offs) {
   Arm64ManagedRegister dst = m_dst.AsArm64();
   Arm64ManagedRegister base = m_base.AsArm64();
-  CHECK(dst.IsCoreRegister() && base.IsCoreRegister());
+  CHECK(dst.IsXRegister() && base.IsXRegister());
   // Remove dst and base form the temp list - higher level API uses IP1, IP0.
   vixl::UseScratchRegisterScope temps(vixl_masm_);
-  temps.Exclude(reg_x(dst.AsCoreRegister()), reg_x(base.AsCoreRegister()));
-  ___ Ldr(reg_x(dst.AsCoreRegister()), MEM_OP(reg_x(base.AsCoreRegister()), offs.Int32Value()));
+  temps.Exclude(reg_x(dst.AsXRegister()), reg_x(base.AsXRegister()));
+  ___ Ldr(reg_x(dst.AsXRegister()), MEM_OP(reg_x(base.AsXRegister()), offs.Int32Value()));
 }
 
 void Arm64Assembler::LoadRawPtrFromThread64(ManagedRegister m_dst, ThreadOffset<8> offs) {
   Arm64ManagedRegister dst = m_dst.AsArm64();
-  CHECK(dst.IsCoreRegister()) << dst;
-  LoadFromOffset(dst.AsCoreRegister(), ETR, offs.Int32Value());
+  CHECK(dst.IsXRegister()) << dst;
+  LoadFromOffset(dst.AsXRegister(), ETR, offs.Int32Value());
 }
 
 // Copying routines.
@@ -326,15 +326,15 @@
   Arm64ManagedRegister dst = m_dst.AsArm64();
   Arm64ManagedRegister src = m_src.AsArm64();
   if (!dst.Equals(src)) {
-    if (dst.IsCoreRegister()) {
+    if (dst.IsXRegister()) {
       if (size == 4) {
         CHECK(src.IsWRegister());
-        ___ Mov(reg_x(dst.AsCoreRegister()), reg_w(src.AsWRegister()));
+        ___ Mov(reg_x(dst.AsXRegister()), reg_w(src.AsWRegister()));
       } else {
-        if (src.IsCoreRegister()) {
-          ___ Mov(reg_x(dst.AsCoreRegister()), reg_x(src.AsCoreRegister()));
+        if (src.IsXRegister()) {
+          ___ Mov(reg_x(dst.AsXRegister()), reg_x(src.AsXRegister()));
         } else {
-          ___ Mov(reg_x(dst.AsCoreRegister()), reg_w(src.AsWRegister()));
+          ___ Mov(reg_x(dst.AsXRegister()), reg_w(src.AsWRegister()));
         }
       }
     } else if (dst.IsWRegister()) {
@@ -355,41 +355,41 @@
                                           ThreadOffset<8> tr_offs,
                                           ManagedRegister m_scratch) {
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
-  CHECK(scratch.IsCoreRegister()) << scratch;
-  LoadFromOffset(scratch.AsCoreRegister(), ETR, tr_offs.Int32Value());
-  StoreToOffset(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
+  CHECK(scratch.IsXRegister()) << scratch;
+  LoadFromOffset(scratch.AsXRegister(), ETR, tr_offs.Int32Value());
+  StoreToOffset(scratch.AsXRegister(), SP, fr_offs.Int32Value());
 }
 
 void Arm64Assembler::CopyRawPtrToThread64(ThreadOffset<8> tr_offs,
                                         FrameOffset fr_offs,
                                         ManagedRegister m_scratch) {
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
-  CHECK(scratch.IsCoreRegister()) << scratch;
-  LoadFromOffset(scratch.AsCoreRegister(), SP, fr_offs.Int32Value());
-  StoreToOffset(scratch.AsCoreRegister(), ETR, tr_offs.Int32Value());
+  CHECK(scratch.IsXRegister()) << scratch;
+  LoadFromOffset(scratch.AsXRegister(), SP, fr_offs.Int32Value());
+  StoreToOffset(scratch.AsXRegister(), ETR, tr_offs.Int32Value());
 }
 
 void Arm64Assembler::CopyRef(FrameOffset dest, FrameOffset src,
                              ManagedRegister m_scratch) {
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
-  CHECK(scratch.IsCoreRegister()) << scratch;
-  LoadWFromOffset(kLoadWord, scratch.AsOverlappingCoreRegisterLow(),
+  CHECK(scratch.IsXRegister()) << scratch;
+  LoadWFromOffset(kLoadWord, scratch.AsOverlappingWRegister(),
                   SP, src.Int32Value());
-  StoreWToOffset(kStoreWord, scratch.AsOverlappingCoreRegisterLow(),
+  StoreWToOffset(kStoreWord, scratch.AsOverlappingWRegister(),
                  SP, dest.Int32Value());
 }
 
 void Arm64Assembler::Copy(FrameOffset dest, FrameOffset src,
                           ManagedRegister m_scratch, size_t size) {
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
-  CHECK(scratch.IsCoreRegister()) << scratch;
+  CHECK(scratch.IsXRegister()) << scratch;
   CHECK(size == 4 || size == 8) << size;
   if (size == 4) {
-    LoadWFromOffset(kLoadWord, scratch.AsOverlappingCoreRegisterLow(), SP, src.Int32Value());
-    StoreWToOffset(kStoreWord, scratch.AsOverlappingCoreRegisterLow(), SP, dest.Int32Value());
+    LoadWFromOffset(kLoadWord, scratch.AsOverlappingWRegister(), SP, src.Int32Value());
+    StoreWToOffset(kStoreWord, scratch.AsOverlappingWRegister(), SP, dest.Int32Value());
   } else if (size == 8) {
-    LoadFromOffset(scratch.AsCoreRegister(), SP, src.Int32Value());
-    StoreToOffset(scratch.AsCoreRegister(), SP, dest.Int32Value());
+    LoadFromOffset(scratch.AsXRegister(), SP, src.Int32Value());
+    StoreToOffset(scratch.AsXRegister(), SP, dest.Int32Value());
   } else {
     UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
   }
@@ -399,16 +399,16 @@
                           ManagedRegister m_scratch, size_t size) {
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
   Arm64ManagedRegister base = src_base.AsArm64();
-  CHECK(base.IsCoreRegister()) << base;
-  CHECK(scratch.IsCoreRegister() || scratch.IsWRegister()) << scratch;
+  CHECK(base.IsXRegister()) << base;
+  CHECK(scratch.IsXRegister() || scratch.IsWRegister()) << scratch;
   CHECK(size == 4 || size == 8) << size;
   if (size == 4) {
-    LoadWFromOffset(kLoadWord, scratch.AsWRegister(), base.AsCoreRegister(),
+    LoadWFromOffset(kLoadWord, scratch.AsWRegister(), base.AsXRegister(),
                    src_offset.Int32Value());
     StoreWToOffset(kStoreWord, scratch.AsWRegister(), SP, dest.Int32Value());
   } else if (size == 8) {
-    LoadFromOffset(scratch.AsCoreRegister(), base.AsCoreRegister(), src_offset.Int32Value());
-    StoreToOffset(scratch.AsCoreRegister(), SP, dest.Int32Value());
+    LoadFromOffset(scratch.AsXRegister(), base.AsXRegister(), src_offset.Int32Value());
+    StoreToOffset(scratch.AsXRegister(), SP, dest.Int32Value());
   } else {
     UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
   }
@@ -418,16 +418,16 @@
                           ManagedRegister m_scratch, size_t size) {
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
   Arm64ManagedRegister base = m_dest_base.AsArm64();
-  CHECK(base.IsCoreRegister()) << base;
-  CHECK(scratch.IsCoreRegister() || scratch.IsWRegister()) << scratch;
+  CHECK(base.IsXRegister()) << base;
+  CHECK(scratch.IsXRegister() || scratch.IsWRegister()) << scratch;
   CHECK(size == 4 || size == 8) << size;
   if (size == 4) {
     LoadWFromOffset(kLoadWord, scratch.AsWRegister(), SP, src.Int32Value());
-    StoreWToOffset(kStoreWord, scratch.AsWRegister(), base.AsCoreRegister(),
+    StoreWToOffset(kStoreWord, scratch.AsWRegister(), base.AsXRegister(),
                    dest_offs.Int32Value());
   } else if (size == 8) {
-    LoadFromOffset(scratch.AsCoreRegister(), SP, src.Int32Value());
-    StoreToOffset(scratch.AsCoreRegister(), base.AsCoreRegister(), dest_offs.Int32Value());
+    LoadFromOffset(scratch.AsXRegister(), SP, src.Int32Value());
+    StoreToOffset(scratch.AsXRegister(), base.AsXRegister(), dest_offs.Int32Value());
   } else {
     UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
   }
@@ -444,25 +444,25 @@
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
   Arm64ManagedRegister src = m_src.AsArm64();
   Arm64ManagedRegister dest = m_dest.AsArm64();
-  CHECK(dest.IsCoreRegister()) << dest;
-  CHECK(src.IsCoreRegister()) << src;
-  CHECK(scratch.IsCoreRegister() || scratch.IsWRegister()) << scratch;
+  CHECK(dest.IsXRegister()) << dest;
+  CHECK(src.IsXRegister()) << src;
+  CHECK(scratch.IsXRegister() || scratch.IsWRegister()) << scratch;
   CHECK(size == 4 || size == 8) << size;
   if (size == 4) {
     if (scratch.IsWRegister()) {
-      LoadWFromOffset(kLoadWord, scratch.AsWRegister(), src.AsCoreRegister(),
+      LoadWFromOffset(kLoadWord, scratch.AsWRegister(), src.AsXRegister(),
                     src_offset.Int32Value());
-      StoreWToOffset(kStoreWord, scratch.AsWRegister(), dest.AsCoreRegister(),
+      StoreWToOffset(kStoreWord, scratch.AsWRegister(), dest.AsXRegister(),
                    dest_offset.Int32Value());
     } else {
-      LoadWFromOffset(kLoadWord, scratch.AsOverlappingCoreRegisterLow(), src.AsCoreRegister(),
+      LoadWFromOffset(kLoadWord, scratch.AsOverlappingWRegister(), src.AsXRegister(),
                     src_offset.Int32Value());
-      StoreWToOffset(kStoreWord, scratch.AsOverlappingCoreRegisterLow(), dest.AsCoreRegister(),
+      StoreWToOffset(kStoreWord, scratch.AsOverlappingWRegister(), dest.AsXRegister(),
                    dest_offset.Int32Value());
     }
   } else if (size == 8) {
-    LoadFromOffset(scratch.AsCoreRegister(), src.AsCoreRegister(), src_offset.Int32Value());
-    StoreToOffset(scratch.AsCoreRegister(), dest.AsCoreRegister(), dest_offset.Int32Value());
+    LoadFromOffset(scratch.AsXRegister(), src.AsXRegister(), src_offset.Int32Value());
+    StoreToOffset(scratch.AsXRegister(), dest.AsXRegister(), dest_offset.Int32Value());
   } else {
     UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8";
   }
@@ -514,31 +514,31 @@
 void Arm64Assembler::Call(ManagedRegister m_base, Offset offs, ManagedRegister m_scratch) {
   Arm64ManagedRegister base = m_base.AsArm64();
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
-  CHECK(base.IsCoreRegister()) << base;
-  CHECK(scratch.IsCoreRegister()) << scratch;
-  LoadFromOffset(scratch.AsCoreRegister(), base.AsCoreRegister(), offs.Int32Value());
-  ___ Blr(reg_x(scratch.AsCoreRegister()));
+  CHECK(base.IsXRegister()) << base;
+  CHECK(scratch.IsXRegister()) << scratch;
+  LoadFromOffset(scratch.AsXRegister(), base.AsXRegister(), offs.Int32Value());
+  ___ Blr(reg_x(scratch.AsXRegister()));
 }
 
 void Arm64Assembler::JumpTo(ManagedRegister m_base, Offset offs, ManagedRegister m_scratch) {
   Arm64ManagedRegister base = m_base.AsArm64();
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
-  CHECK(base.IsCoreRegister()) << base;
-  CHECK(scratch.IsCoreRegister()) << scratch;
+  CHECK(base.IsXRegister()) << base;
+  CHECK(scratch.IsXRegister()) << scratch;
   // Remove base and scratch form the temp list - higher level API uses IP1, IP0.
   vixl::UseScratchRegisterScope temps(vixl_masm_);
-  temps.Exclude(reg_x(base.AsCoreRegister()), reg_x(scratch.AsCoreRegister()));
-  ___ Ldr(reg_x(scratch.AsCoreRegister()), MEM_OP(reg_x(base.AsCoreRegister()), offs.Int32Value()));
-  ___ Br(reg_x(scratch.AsCoreRegister()));
+  temps.Exclude(reg_x(base.AsXRegister()), reg_x(scratch.AsXRegister()));
+  ___ Ldr(reg_x(scratch.AsXRegister()), MEM_OP(reg_x(base.AsXRegister()), offs.Int32Value()));
+  ___ Br(reg_x(scratch.AsXRegister()));
 }
 
 void Arm64Assembler::Call(FrameOffset base, Offset offs, ManagedRegister m_scratch) {
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
-  CHECK(scratch.IsCoreRegister()) << scratch;
+  CHECK(scratch.IsXRegister()) << scratch;
   // Call *(*(SP + base) + offset)
-  LoadWFromOffset(kLoadWord, scratch.AsOverlappingCoreRegisterLow(), SP, base.Int32Value());
-  LoadFromOffset(scratch.AsCoreRegister(), scratch.AsCoreRegister(), offs.Int32Value());
-  ___ Blr(reg_x(scratch.AsCoreRegister()));
+  LoadWFromOffset(kLoadWord, scratch.AsOverlappingWRegister(), SP, base.Int32Value());
+  LoadFromOffset(scratch.AsXRegister(), scratch.AsXRegister(), offs.Int32Value());
+  ___ Blr(reg_x(scratch.AsXRegister()));
 }
 
 void Arm64Assembler::CallFromThread64(ThreadOffset<8> /*offset*/, ManagedRegister /*scratch*/) {
@@ -550,59 +550,59 @@
   Arm64ManagedRegister out_reg = m_out_reg.AsArm64();
   Arm64ManagedRegister in_reg = m_in_reg.AsArm64();
   // For now we only hold stale handle scope entries in x registers.
-  CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg;
-  CHECK(out_reg.IsCoreRegister()) << out_reg;
+  CHECK(in_reg.IsNoRegister() || in_reg.IsXRegister()) << in_reg;
+  CHECK(out_reg.IsXRegister()) << out_reg;
   if (null_allowed) {
     // Null values get a handle scope entry value of 0.  Otherwise, the handle scope entry is
     // the address in the handle scope holding the reference.
     // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset)
     if (in_reg.IsNoRegister()) {
-      LoadWFromOffset(kLoadWord, out_reg.AsOverlappingCoreRegisterLow(), SP,
+      LoadWFromOffset(kLoadWord, out_reg.AsOverlappingWRegister(), SP,
                       handle_scope_offs.Int32Value());
       in_reg = out_reg;
     }
-    ___ Cmp(reg_w(in_reg.AsOverlappingCoreRegisterLow()), 0);
+    ___ Cmp(reg_w(in_reg.AsOverlappingWRegister()), 0);
     if (!out_reg.Equals(in_reg)) {
-      LoadImmediate(out_reg.AsCoreRegister(), 0, eq);
+      LoadImmediate(out_reg.AsXRegister(), 0, eq);
     }
-    AddConstant(out_reg.AsCoreRegister(), SP, handle_scope_offs.Int32Value(), ne);
+    AddConstant(out_reg.AsXRegister(), SP, handle_scope_offs.Int32Value(), ne);
   } else {
-    AddConstant(out_reg.AsCoreRegister(), SP, handle_scope_offs.Int32Value(), al);
+    AddConstant(out_reg.AsXRegister(), SP, handle_scope_offs.Int32Value(), al);
   }
 }
 
 void Arm64Assembler::CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handle_scope_offset,
                                      ManagedRegister m_scratch, bool null_allowed) {
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
-  CHECK(scratch.IsCoreRegister()) << scratch;
+  CHECK(scratch.IsXRegister()) << scratch;
   if (null_allowed) {
-    LoadWFromOffset(kLoadWord, scratch.AsOverlappingCoreRegisterLow(), SP,
+    LoadWFromOffset(kLoadWord, scratch.AsOverlappingWRegister(), SP,
                     handle_scope_offset.Int32Value());
     // Null values get a handle scope entry value of 0.  Otherwise, the handle scope entry is
     // the address in the handle scope holding the reference.
     // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset)
-    ___ Cmp(reg_w(scratch.AsOverlappingCoreRegisterLow()), 0);
+    ___ Cmp(reg_w(scratch.AsOverlappingWRegister()), 0);
     // Move this logic in add constants with flags.
-    AddConstant(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value(), ne);
+    AddConstant(scratch.AsXRegister(), SP, handle_scope_offset.Int32Value(), ne);
   } else {
-    AddConstant(scratch.AsCoreRegister(), SP, handle_scope_offset.Int32Value(), al);
+    AddConstant(scratch.AsXRegister(), SP, handle_scope_offset.Int32Value(), al);
   }
-  StoreToOffset(scratch.AsCoreRegister(), SP, out_off.Int32Value());
+  StoreToOffset(scratch.AsXRegister(), SP, out_off.Int32Value());
 }
 
 void Arm64Assembler::LoadReferenceFromHandleScope(ManagedRegister m_out_reg,
                                            ManagedRegister m_in_reg) {
   Arm64ManagedRegister out_reg = m_out_reg.AsArm64();
   Arm64ManagedRegister in_reg = m_in_reg.AsArm64();
-  CHECK(out_reg.IsCoreRegister()) << out_reg;
-  CHECK(in_reg.IsCoreRegister()) << in_reg;
+  CHECK(out_reg.IsXRegister()) << out_reg;
+  CHECK(in_reg.IsXRegister()) << in_reg;
   vixl::Label exit;
   if (!out_reg.Equals(in_reg)) {
     // FIXME: Who sets the flags here?
-    LoadImmediate(out_reg.AsCoreRegister(), 0, eq);
+    LoadImmediate(out_reg.AsXRegister(), 0, eq);
   }
-  ___ Cbz(reg_x(in_reg.AsCoreRegister()), &exit);
-  LoadFromOffset(out_reg.AsCoreRegister(), in_reg.AsCoreRegister(), 0);
+  ___ Cbz(reg_x(in_reg.AsXRegister()), &exit);
+  LoadFromOffset(out_reg.AsXRegister(), in_reg.AsXRegister(), 0);
   ___ Bind(&exit);
 }
 
@@ -611,13 +611,13 @@
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
   Arm64Exception *current_exception = new Arm64Exception(scratch, stack_adjust);
   exception_blocks_.push_back(current_exception);
-  LoadFromOffset(scratch.AsCoreRegister(), ETR, Thread::ExceptionOffset<8>().Int32Value());
-  ___ Cbnz(reg_x(scratch.AsCoreRegister()), current_exception->Entry());
+  LoadFromOffset(scratch.AsXRegister(), ETR, Thread::ExceptionOffset<8>().Int32Value());
+  ___ Cbnz(reg_x(scratch.AsXRegister()), current_exception->Entry());
 }
 
 void Arm64Assembler::EmitExceptionPoll(Arm64Exception *exception) {
   vixl::UseScratchRegisterScope temps(vixl_masm_);
-  temps.Exclude(reg_x(exception->scratch_.AsCoreRegister()));
+  temps.Exclude(reg_x(exception->scratch_.AsXRegister()));
   vixl::Register temp = temps.AcquireX();
 
   // Bind exception poll entry.
@@ -627,7 +627,7 @@
   }
   // Pass exception object as argument.
   // Don't care about preserving X0 as this won't return.
-  ___ Mov(reg_x(X0), reg_x(exception->scratch_.AsCoreRegister()));
+  ___ Mov(reg_x(X0), reg_x(exception->scratch_.AsXRegister()));
   ___ Ldr(temp, MEM_OP(reg_x(ETR), QUICK_ENTRYPOINT_OFFSET(8, pDeliverException).Int32Value()));
 
   // Move ETR(Callee saved) back to TR(Caller saved) reg. We use ETR on calls
@@ -646,7 +646,7 @@
                         const std::vector<ManagedRegister>& callee_save_regs,
                         const ManagedRegisterEntrySpills& entry_spills) {
   CHECK_ALIGNED(frame_size, kStackAlignment);
-  CHECK(X0 == method_reg.AsArm64().AsCoreRegister());
+  CHECK(X0 == method_reg.AsArm64().AsXRegister());
 
   // TODO: *create APCS FP - end of FP chain;
   //       *add support for saving a different set of callee regs.
@@ -700,8 +700,8 @@
       // only increment stack offset.
       ManagedRegisterSpill spill = entry_spills.at(i);
       offset += spill.getSize();
-    } else if (reg.IsCoreRegister()) {
-      StoreToOffset(reg.AsCoreRegister(), SP, offset);
+    } else if (reg.IsXRegister()) {
+      StoreToOffset(reg.AsXRegister(), SP, offset);
       offset += 8;
     } else if (reg.IsWRegister()) {
       StoreWToOffset(kStoreWord, reg.AsWRegister(), SP, offset);
diff --git a/compiler/utils/arm64/assembler_arm64.h b/compiler/utils/arm64/assembler_arm64.h
index ef83334..1b1d121 100644
--- a/compiler/utils/arm64/assembler_arm64.h
+++ b/compiler/utils/arm64/assembler_arm64.h
@@ -173,7 +173,7 @@
 
  private:
   static vixl::Register reg_x(int code) {
-    CHECK(code < kNumberOfCoreRegisters) << code;
+    CHECK(code < kNumberOfXRegisters) << code;
     if (code == SP) {
       return vixl::sp;
     } else if (code == XZR) {
@@ -183,6 +183,12 @@
   }
 
   static vixl::Register reg_w(int code) {
+    CHECK(code < kNumberOfWRegisters) << code;
+    if (code == WSP) {
+      return vixl::wsp;
+    } else if (code == WZR) {
+      return vixl::wzr;
+    }
     return vixl::Register::WRegFromCode(code);
   }
 
@@ -198,27 +204,28 @@
   void EmitExceptionPoll(Arm64Exception *exception);
 
   void StoreWToOffset(StoreOperandType type, WRegister source,
-                      Register base, int32_t offset);
-  void StoreToOffset(Register source, Register base, int32_t offset);
-  void StoreSToOffset(SRegister source, Register base, int32_t offset);
-  void StoreDToOffset(DRegister source, Register base, int32_t offset);
+                      XRegister base, int32_t offset);
+  void StoreToOffset(XRegister source, XRegister base, int32_t offset);
+  void StoreSToOffset(SRegister source, XRegister base, int32_t offset);
+  void StoreDToOffset(DRegister source, XRegister base, int32_t offset);
 
-  void LoadImmediate(Register dest, int32_t value, vixl::Condition cond = vixl::al);
-  void Load(Arm64ManagedRegister dst, Register src, int32_t src_offset, size_t size);
+  void LoadImmediate(XRegister dest, int32_t value, vixl::Condition cond = vixl::al);
+  void Load(Arm64ManagedRegister dst, XRegister src, int32_t src_offset, size_t size);
   void LoadWFromOffset(LoadOperandType type, WRegister dest,
-                      Register base, int32_t offset);
-  void LoadFromOffset(Register dest, Register base, int32_t offset);
-  void LoadSFromOffset(SRegister dest, Register base, int32_t offset);
-  void LoadDFromOffset(DRegister dest, Register base, int32_t offset);
-  void AddConstant(Register rd, int32_t value, vixl::Condition cond = vixl::al);
-  void AddConstant(Register rd, Register rn, int32_t value, vixl::Condition cond = vixl::al);
-
-  // Vixl assembler.
-  vixl::MacroAssembler* const vixl_masm_;
+                      XRegister base, int32_t offset);
+  void LoadFromOffset(XRegister dest, XRegister base, int32_t offset);
+  void LoadSFromOffset(SRegister dest, XRegister base, int32_t offset);
+  void LoadDFromOffset(DRegister dest, XRegister base, int32_t offset);
+  void AddConstant(XRegister rd, int32_t value, vixl::Condition cond = vixl::al);
+  void AddConstant(XRegister rd, XRegister rn, int32_t value, vixl::Condition cond = vixl::al);
 
   // List of exception blocks to generate at the end of the code cache.
   std::vector<Arm64Exception*> exception_blocks_;
 
+ public:
+  // Vixl assembler.
+  vixl::MacroAssembler* const vixl_masm_;
+
   // Used for testing.
   friend class Arm64ManagedRegister_VixlRegisters_Test;
 };
diff --git a/compiler/utils/arm64/managed_register_arm64.cc b/compiler/utils/arm64/managed_register_arm64.cc
index 8977313..47924bf 100644
--- a/compiler/utils/arm64/managed_register_arm64.cc
+++ b/compiler/utils/arm64/managed_register_arm64.cc
@@ -27,7 +27,7 @@
 //  * [W0, W15]
 //  * [D0, D31]
 //  * [S0, S31]
-// static const int kNumberOfAvailableCoreRegisters = (X15 - X0) + 1;
+// static const int kNumberOfAvailableXRegisters = (X15 - X0) + 1;
 // static const int kNumberOfAvailableWRegisters = (W15 - W0) + 1;
 // static const int kNumberOfAvailableDRegisters = kNumberOfDRegisters;
 // static const int kNumberOfAvailableSRegisters = kNumberOfSRegisters;
@@ -42,22 +42,14 @@
 // 63__________0 D[n]
 bool Arm64ManagedRegister::Overlaps(const Arm64ManagedRegister& other) const {
   if (IsNoRegister() || other.IsNoRegister()) return false;
-  if ((IsGPRegister() && other.IsGPRegister()) ||
-      (IsFPRegister() && other.IsFPRegister())) {
-    return (RegNo() == other.RegNo());
-  }
-  return false;
+  return (IsGPRegister() == other.IsGPRegister()) && (RegNo() == other.RegNo());
 }
 
 int Arm64ManagedRegister::RegNo() const {
   CHECK(!IsNoRegister());
   int no;
-  if (IsCoreRegister()) {
-    if (IsZeroRegister()) {
-      no = static_cast<int>(X31);
-    } else {
-      no = static_cast<int>(AsCoreRegister());
-    }
+  if (IsXRegister()) {
+    no = static_cast<int>(AsXRegister());
   } else if (IsWRegister()) {
     no = static_cast<int>(AsWRegister());
   } else if (IsDRegister()) {
@@ -71,12 +63,12 @@
 }
 
 int Arm64ManagedRegister::RegIdLow() const {
-  CHECK(IsCoreRegister() || IsDRegister());
+  CHECK(IsXRegister() || IsDRegister());
   int low = RegNo();
-  if (IsCoreRegister()) {
-    low += kNumberOfCoreRegIds;
+  if (IsXRegister()) {
+    low += kNumberOfXRegIds;
   } else if (IsDRegister()) {
-    low += kNumberOfCoreRegIds + kNumberOfWRegIds + kNumberOfDRegIds;
+    low += kNumberOfXRegIds + kNumberOfWRegIds + kNumberOfDRegIds;
   }
   return low;
 }
@@ -86,7 +78,7 @@
   CHECK(IsWRegister() || IsSRegister());
   int high = RegNo();
   if (IsSRegister()) {
-    high += kNumberOfCoreRegIds + kNumberOfWRegIds;
+    high += kNumberOfXRegIds + kNumberOfWRegIds;
   }
   return high;
 }
@@ -94,8 +86,8 @@
 void Arm64ManagedRegister::Print(std::ostream& os) const {
   if (!IsValidManagedRegister()) {
     os << "No Register";
-  } else if (IsCoreRegister()) {
-    os << "XCore: " << static_cast<int>(AsCoreRegister());
+  } else if (IsXRegister()) {
+    os << "XCore: " << static_cast<int>(AsXRegister());
   } else if (IsWRegister()) {
     os << "WCore: " << static_cast<int>(AsWRegister());
   } else if (IsDRegister()) {
diff --git a/compiler/utils/arm64/managed_register_arm64.h b/compiler/utils/arm64/managed_register_arm64.h
index a0f520f..e1d6f31 100644
--- a/compiler/utils/arm64/managed_register_arm64.h
+++ b/compiler/utils/arm64/managed_register_arm64.h
@@ -24,29 +24,29 @@
 namespace art {
 namespace arm64 {
 
-const int kNumberOfCoreRegIds = kNumberOfCoreRegisters;
+const int kNumberOfXRegIds = kNumberOfXRegisters;
 const int kNumberOfWRegIds = kNumberOfWRegisters;
 const int kNumberOfDRegIds = kNumberOfDRegisters;
 const int kNumberOfSRegIds = kNumberOfSRegisters;
 
-const int kNumberOfRegIds = kNumberOfCoreRegIds + kNumberOfWRegIds +
+const int kNumberOfRegIds = kNumberOfXRegIds + kNumberOfWRegIds +
   kNumberOfDRegIds + kNumberOfSRegIds;
 
 // Register ids map:
-//  [0..X[  core registers 64bit (enum Register)
+//  [0..X[  core registers 64bit (enum XRegister)
 //  [X..W[  core registers 32bit (enum WRegister)
 //  [W..D[  double precision VFP registers (enum DRegister)
 //  [D..S[  single precision VFP registers (enum SRegister)
 //
 // where:
-//  X = kNumberOfCoreRegIds
+//  X = kNumberOfXRegIds
 //  W = X + kNumberOfWRegIds
 //  D = W + kNumberOfDRegIds
 //  S = D + kNumberOfSRegIds
 //
 // An instance of class 'ManagedRegister' represents a single Arm64
 // register. A register can be one of the following:
-//  * core register 64bit context (enum Register)
+//  * core register 64bit context (enum XRegister)
 //  * core register 32bit context (enum WRegister)
 //  * VFP double precision register (enum DRegister)
 //  * VFP single precision register (enum SRegister)
@@ -55,76 +55,74 @@
 
 class Arm64ManagedRegister : public ManagedRegister {
  public:
-  Register AsCoreRegister() const {
-    CHECK(IsCoreRegister());
-    return static_cast<Register>(id_);
+  XRegister AsXRegister() const {
+    CHECK(IsXRegister());
+    return static_cast<XRegister>(id_);
   }
 
   WRegister AsWRegister() const {
     CHECK(IsWRegister());
-    return static_cast<WRegister>(id_ - kNumberOfCoreRegIds);
+    return static_cast<WRegister>(id_ - kNumberOfXRegIds);
   }
 
   DRegister AsDRegister() const {
     CHECK(IsDRegister());
-    return static_cast<DRegister>(id_ - kNumberOfCoreRegIds - kNumberOfWRegIds);
+    return static_cast<DRegister>(id_ - kNumberOfXRegIds - kNumberOfWRegIds);
   }
 
   SRegister AsSRegister() const {
     CHECK(IsSRegister());
-    return static_cast<SRegister>(id_ - kNumberOfCoreRegIds - kNumberOfWRegIds -
+    return static_cast<SRegister>(id_ - kNumberOfXRegIds - kNumberOfWRegIds -
                                   kNumberOfDRegIds);
   }
 
-  WRegister AsOverlappingCoreRegisterLow() const {
+  WRegister AsOverlappingWRegister() const {
     CHECK(IsValidManagedRegister());
-    if (IsZeroRegister()) return W31;
-    return static_cast<WRegister>(AsCoreRegister());
+    if (IsZeroRegister()) return WZR;
+    return static_cast<WRegister>(AsXRegister());
   }
 
-  // FIXME: Find better naming.
-  Register AsOverlappingWRegisterCore() const {
+  XRegister AsOverlappingXRegister() const {
     CHECK(IsValidManagedRegister());
-    return static_cast<Register>(AsWRegister());
+    return static_cast<XRegister>(AsWRegister());
   }
 
-  SRegister AsOverlappingDRegisterLow() const {
+  SRegister AsOverlappingSRegister() const {
     CHECK(IsValidManagedRegister());
     return static_cast<SRegister>(AsDRegister());
   }
 
-  // FIXME: Find better naming.
-  DRegister AsOverlappingSRegisterD() const {
+  DRegister AsOverlappingDRegister() const {
     CHECK(IsValidManagedRegister());
     return static_cast<DRegister>(AsSRegister());
   }
 
-  bool IsCoreRegister() const {
+  bool IsXRegister() const {
     CHECK(IsValidManagedRegister());
-    return (0 <= id_) && (id_ < kNumberOfCoreRegIds);
+    return (0 <= id_) && (id_ < kNumberOfXRegIds);
   }
 
   bool IsWRegister() const {
     CHECK(IsValidManagedRegister());
-    const int test = id_ - kNumberOfCoreRegIds;
+    const int test = id_ - kNumberOfXRegIds;
     return (0 <= test) && (test < kNumberOfWRegIds);
   }
 
   bool IsDRegister() const {
     CHECK(IsValidManagedRegister());
-    const int test = id_ - (kNumberOfCoreRegIds + kNumberOfWRegIds);
+    const int test = id_ - (kNumberOfXRegIds + kNumberOfWRegIds);
     return (0 <= test) && (test < kNumberOfDRegIds);
   }
 
   bool IsSRegister() const {
     CHECK(IsValidManagedRegister());
-    const int test = id_ - (kNumberOfCoreRegIds + kNumberOfWRegIds +
+    const int test = id_ - (kNumberOfXRegIds + kNumberOfWRegIds +
                             kNumberOfDRegIds);
     return (0 <= test) && (test < kNumberOfSRegIds);
   }
 
   bool IsGPRegister() const {
-    return IsCoreRegister() || IsWRegister();
+    return IsXRegister() || IsWRegister();
   }
 
   bool IsFPRegister() const {
@@ -134,7 +132,7 @@
   bool IsSameType(Arm64ManagedRegister test) const {
     CHECK(IsValidManagedRegister() && test.IsValidManagedRegister());
     return
-      (IsCoreRegister() && test.IsCoreRegister()) ||
+      (IsXRegister() && test.IsXRegister()) ||
       (IsWRegister() && test.IsWRegister()) ||
       (IsDRegister() && test.IsDRegister()) ||
       (IsSRegister() && test.IsSRegister());
@@ -147,29 +145,29 @@
 
   void Print(std::ostream& os) const;
 
-  static Arm64ManagedRegister FromCoreRegister(Register r) {
+  static Arm64ManagedRegister FromXRegister(XRegister r) {
     CHECK_NE(r, kNoRegister);
     return FromRegId(r);
   }
 
   static Arm64ManagedRegister FromWRegister(WRegister r) {
     CHECK_NE(r, kNoWRegister);
-    return FromRegId(r + kNumberOfCoreRegIds);
+    return FromRegId(r + kNumberOfXRegIds);
   }
 
   static Arm64ManagedRegister FromDRegister(DRegister r) {
     CHECK_NE(r, kNoDRegister);
-    return FromRegId(r + (kNumberOfCoreRegIds + kNumberOfWRegIds));
+    return FromRegId(r + (kNumberOfXRegIds + kNumberOfWRegIds));
   }
 
   static Arm64ManagedRegister FromSRegister(SRegister r) {
     CHECK_NE(r, kNoSRegister);
-    return FromRegId(r + (kNumberOfCoreRegIds + kNumberOfWRegIds +
+    return FromRegId(r + (kNumberOfXRegIds + kNumberOfWRegIds +
                           kNumberOfDRegIds));
   }
 
   // Returns the X register overlapping W register r.
-  static Arm64ManagedRegister FromWRegisterCore(WRegister r) {
+  static Arm64ManagedRegister FromWRegisterX(WRegister r) {
     CHECK_NE(r, kNoWRegister);
     return FromRegId(r);
   }
@@ -177,7 +175,7 @@
   // Return the D register overlapping S register r.
   static Arm64ManagedRegister FromSRegisterD(SRegister r) {
     CHECK_NE(r, kNoSRegister);
-    return FromRegId(r + (kNumberOfCoreRegIds + kNumberOfWRegIds));
+    return FromRegId(r + (kNumberOfXRegIds + kNumberOfWRegIds));
   }
 
  private:
@@ -186,11 +184,11 @@
   }
 
   bool IsStackPointer() const {
-    return IsCoreRegister() && (id_ == SP);
+    return IsXRegister() && (id_ == SP);
   }
 
   bool IsZeroRegister() const {
-    return IsCoreRegister() && (id_ == XZR);
+    return IsXRegister() && (id_ == XZR);
   }
 
   int RegId() const {
diff --git a/compiler/utils/arm64/managed_register_arm64_test.cc b/compiler/utils/arm64/managed_register_arm64_test.cc
index f149f1b..32c2e62 100644
--- a/compiler/utils/arm64/managed_register_arm64_test.cc
+++ b/compiler/utils/arm64/managed_register_arm64_test.cc
@@ -29,84 +29,84 @@
 }
 
 // X Register test.
-TEST(Arm64ManagedRegister, CoreRegister) {
-  Arm64ManagedRegister reg = Arm64ManagedRegister::FromCoreRegister(X0);
+TEST(Arm64ManagedRegister, XRegister) {
+  Arm64ManagedRegister reg = Arm64ManagedRegister::FromXRegister(X0);
   Arm64ManagedRegister wreg = Arm64ManagedRegister::FromWRegister(W0);
   EXPECT_TRUE(!reg.IsNoRegister());
-  EXPECT_TRUE(reg.IsCoreRegister());
+  EXPECT_TRUE(reg.IsXRegister());
   EXPECT_TRUE(!reg.IsWRegister());
   EXPECT_TRUE(!reg.IsDRegister());
   EXPECT_TRUE(!reg.IsSRegister());
   EXPECT_TRUE(reg.Overlaps(wreg));
-  EXPECT_EQ(X0, reg.AsCoreRegister());
+  EXPECT_EQ(X0, reg.AsXRegister());
 
-  reg = Arm64ManagedRegister::FromCoreRegister(X1);
+  reg = Arm64ManagedRegister::FromXRegister(X1);
   wreg = Arm64ManagedRegister::FromWRegister(W1);
   EXPECT_TRUE(!reg.IsNoRegister());
-  EXPECT_TRUE(reg.IsCoreRegister());
+  EXPECT_TRUE(reg.IsXRegister());
   EXPECT_TRUE(!reg.IsWRegister());
   EXPECT_TRUE(!reg.IsDRegister());
   EXPECT_TRUE(!reg.IsSRegister());
   EXPECT_TRUE(reg.Overlaps(wreg));
-  EXPECT_EQ(X1, reg.AsCoreRegister());
+  EXPECT_EQ(X1, reg.AsXRegister());
 
-  reg = Arm64ManagedRegister::FromCoreRegister(X7);
+  reg = Arm64ManagedRegister::FromXRegister(X7);
   wreg = Arm64ManagedRegister::FromWRegister(W7);
   EXPECT_TRUE(!reg.IsNoRegister());
-  EXPECT_TRUE(reg.IsCoreRegister());
+  EXPECT_TRUE(reg.IsXRegister());
   EXPECT_TRUE(!reg.IsWRegister());
   EXPECT_TRUE(!reg.IsDRegister());
   EXPECT_TRUE(!reg.IsSRegister());
   EXPECT_TRUE(reg.Overlaps(wreg));
-  EXPECT_EQ(X7, reg.AsCoreRegister());
+  EXPECT_EQ(X7, reg.AsXRegister());
 
-  reg = Arm64ManagedRegister::FromCoreRegister(X15);
+  reg = Arm64ManagedRegister::FromXRegister(X15);
   wreg = Arm64ManagedRegister::FromWRegister(W15);
   EXPECT_TRUE(!reg.IsNoRegister());
-  EXPECT_TRUE(reg.IsCoreRegister());
+  EXPECT_TRUE(reg.IsXRegister());
   EXPECT_TRUE(!reg.IsWRegister());
   EXPECT_TRUE(!reg.IsDRegister());
   EXPECT_TRUE(!reg.IsSRegister());
   EXPECT_TRUE(reg.Overlaps(wreg));
-  EXPECT_EQ(X15, reg.AsCoreRegister());
+  EXPECT_EQ(X15, reg.AsXRegister());
 
-  reg = Arm64ManagedRegister::FromCoreRegister(X19);
+  reg = Arm64ManagedRegister::FromXRegister(X19);
   wreg = Arm64ManagedRegister::FromWRegister(W19);
   EXPECT_TRUE(!reg.IsNoRegister());
-  EXPECT_TRUE(reg.IsCoreRegister());
+  EXPECT_TRUE(reg.IsXRegister());
   EXPECT_TRUE(!reg.IsWRegister());
   EXPECT_TRUE(!reg.IsDRegister());
   EXPECT_TRUE(!reg.IsSRegister());
   EXPECT_TRUE(reg.Overlaps(wreg));
-  EXPECT_EQ(X19, reg.AsCoreRegister());
+  EXPECT_EQ(X19, reg.AsXRegister());
 
-  reg = Arm64ManagedRegister::FromCoreRegister(X16);
+  reg = Arm64ManagedRegister::FromXRegister(X16);
   wreg = Arm64ManagedRegister::FromWRegister(W16);
   EXPECT_TRUE(!reg.IsNoRegister());
-  EXPECT_TRUE(reg.IsCoreRegister());
+  EXPECT_TRUE(reg.IsXRegister());
   EXPECT_TRUE(!reg.IsWRegister());
   EXPECT_TRUE(!reg.IsDRegister());
   EXPECT_TRUE(!reg.IsSRegister());
   EXPECT_TRUE(reg.Overlaps(wreg));
-  EXPECT_EQ(IP0, reg.AsCoreRegister());
+  EXPECT_EQ(IP0, reg.AsXRegister());
 
-  reg = Arm64ManagedRegister::FromCoreRegister(SP);
+  reg = Arm64ManagedRegister::FromXRegister(SP);
   wreg = Arm64ManagedRegister::FromWRegister(WZR);
   EXPECT_TRUE(!reg.IsNoRegister());
-  EXPECT_TRUE(reg.IsCoreRegister());
+  EXPECT_TRUE(reg.IsXRegister());
   EXPECT_TRUE(!reg.IsWRegister());
   EXPECT_TRUE(!reg.IsDRegister());
   EXPECT_TRUE(!reg.IsSRegister());
-  EXPECT_TRUE(reg.Overlaps(wreg));
-  EXPECT_EQ(SP, reg.AsCoreRegister());
+  EXPECT_TRUE(!reg.Overlaps(wreg));
+  EXPECT_EQ(SP, reg.AsXRegister());
 }
 
 // W register test.
 TEST(Arm64ManagedRegister, WRegister) {
   Arm64ManagedRegister reg = Arm64ManagedRegister::FromWRegister(W0);
-  Arm64ManagedRegister xreg = Arm64ManagedRegister::FromCoreRegister(X0);
+  Arm64ManagedRegister xreg = Arm64ManagedRegister::FromXRegister(X0);
   EXPECT_TRUE(!reg.IsNoRegister());
-  EXPECT_TRUE(!reg.IsCoreRegister());
+  EXPECT_TRUE(!reg.IsXRegister());
   EXPECT_TRUE(reg.IsWRegister());
   EXPECT_TRUE(!reg.IsDRegister());
   EXPECT_TRUE(!reg.IsSRegister());
@@ -114,9 +114,9 @@
   EXPECT_EQ(W0, reg.AsWRegister());
 
   reg = Arm64ManagedRegister::FromWRegister(W5);
-  xreg = Arm64ManagedRegister::FromCoreRegister(X5);
+  xreg = Arm64ManagedRegister::FromXRegister(X5);
   EXPECT_TRUE(!reg.IsNoRegister());
-  EXPECT_TRUE(!reg.IsCoreRegister());
+  EXPECT_TRUE(!reg.IsXRegister());
   EXPECT_TRUE(reg.IsWRegister());
   EXPECT_TRUE(!reg.IsDRegister());
   EXPECT_TRUE(!reg.IsSRegister());
@@ -124,9 +124,9 @@
   EXPECT_EQ(W5, reg.AsWRegister());
 
   reg = Arm64ManagedRegister::FromWRegister(W6);
-  xreg = Arm64ManagedRegister::FromCoreRegister(X6);
+  xreg = Arm64ManagedRegister::FromXRegister(X6);
   EXPECT_TRUE(!reg.IsNoRegister());
-  EXPECT_TRUE(!reg.IsCoreRegister());
+  EXPECT_TRUE(!reg.IsXRegister());
   EXPECT_TRUE(reg.IsWRegister());
   EXPECT_TRUE(!reg.IsDRegister());
   EXPECT_TRUE(!reg.IsSRegister());
@@ -134,9 +134,9 @@
   EXPECT_EQ(W6, reg.AsWRegister());
 
   reg = Arm64ManagedRegister::FromWRegister(W18);
-  xreg = Arm64ManagedRegister::FromCoreRegister(X18);
+  xreg = Arm64ManagedRegister::FromXRegister(X18);
   EXPECT_TRUE(!reg.IsNoRegister());
-  EXPECT_TRUE(!reg.IsCoreRegister());
+  EXPECT_TRUE(!reg.IsXRegister());
   EXPECT_TRUE(reg.IsWRegister());
   EXPECT_TRUE(!reg.IsDRegister());
   EXPECT_TRUE(!reg.IsSRegister());
@@ -144,9 +144,9 @@
   EXPECT_EQ(W18, reg.AsWRegister());
 
   reg = Arm64ManagedRegister::FromWRegister(W29);
-  xreg = Arm64ManagedRegister::FromCoreRegister(FP);
+  xreg = Arm64ManagedRegister::FromXRegister(FP);
   EXPECT_TRUE(!reg.IsNoRegister());
-  EXPECT_TRUE(!reg.IsCoreRegister());
+  EXPECT_TRUE(!reg.IsXRegister());
   EXPECT_TRUE(reg.IsWRegister());
   EXPECT_TRUE(!reg.IsDRegister());
   EXPECT_TRUE(!reg.IsSRegister());
@@ -154,14 +154,13 @@
   EXPECT_EQ(W29, reg.AsWRegister());
 
   reg = Arm64ManagedRegister::FromWRegister(WZR);
-  xreg = Arm64ManagedRegister::FromCoreRegister(SP);
+  xreg = Arm64ManagedRegister::FromXRegister(SP);
   EXPECT_TRUE(!reg.IsNoRegister());
-  EXPECT_TRUE(!reg.IsCoreRegister());
+  EXPECT_TRUE(!reg.IsXRegister());
   EXPECT_TRUE(reg.IsWRegister());
   EXPECT_TRUE(!reg.IsDRegister());
   EXPECT_TRUE(!reg.IsSRegister());
-  EXPECT_TRUE(reg.Overlaps(xreg));
-  EXPECT_EQ(W31, reg.AsWRegister());
+  EXPECT_TRUE(!reg.Overlaps(xreg));
 }
 
 // D Register test.
@@ -169,49 +168,49 @@
   Arm64ManagedRegister reg = Arm64ManagedRegister::FromDRegister(D0);
   Arm64ManagedRegister sreg = Arm64ManagedRegister::FromSRegister(S0);
   EXPECT_TRUE(!reg.IsNoRegister());
-  EXPECT_TRUE(!reg.IsCoreRegister());
+  EXPECT_TRUE(!reg.IsXRegister());
   EXPECT_TRUE(!reg.IsWRegister());
   EXPECT_TRUE(reg.IsDRegister());
   EXPECT_TRUE(!reg.IsSRegister());
   EXPECT_TRUE(reg.Overlaps(sreg));
   EXPECT_EQ(D0, reg.AsDRegister());
-  EXPECT_EQ(S0, reg.AsOverlappingDRegisterLow());
+  EXPECT_EQ(S0, reg.AsOverlappingSRegister());
   EXPECT_TRUE(reg.Equals(Arm64ManagedRegister::FromDRegister(D0)));
 
   reg = Arm64ManagedRegister::FromDRegister(D1);
   sreg = Arm64ManagedRegister::FromSRegister(S1);
   EXPECT_TRUE(!reg.IsNoRegister());
-  EXPECT_TRUE(!reg.IsCoreRegister());
+  EXPECT_TRUE(!reg.IsXRegister());
   EXPECT_TRUE(!reg.IsWRegister());
   EXPECT_TRUE(reg.IsDRegister());
   EXPECT_TRUE(!reg.IsSRegister());
   EXPECT_TRUE(reg.Overlaps(sreg));
   EXPECT_EQ(D1, reg.AsDRegister());
-  EXPECT_EQ(S1, reg.AsOverlappingDRegisterLow());
+  EXPECT_EQ(S1, reg.AsOverlappingSRegister());
   EXPECT_TRUE(reg.Equals(Arm64ManagedRegister::FromDRegister(D1)));
 
   reg = Arm64ManagedRegister::FromDRegister(D20);
   sreg = Arm64ManagedRegister::FromSRegister(S20);
   EXPECT_TRUE(!reg.IsNoRegister());
-  EXPECT_TRUE(!reg.IsCoreRegister());
+  EXPECT_TRUE(!reg.IsXRegister());
   EXPECT_TRUE(!reg.IsWRegister());
   EXPECT_TRUE(reg.IsDRegister());
   EXPECT_TRUE(!reg.IsSRegister());
   EXPECT_TRUE(reg.Overlaps(sreg));
   EXPECT_EQ(D20, reg.AsDRegister());
-  EXPECT_EQ(S20, reg.AsOverlappingDRegisterLow());
+  EXPECT_EQ(S20, reg.AsOverlappingSRegister());
   EXPECT_TRUE(reg.Equals(Arm64ManagedRegister::FromDRegister(D20)));
 
   reg = Arm64ManagedRegister::FromDRegister(D31);
   sreg = Arm64ManagedRegister::FromSRegister(S31);
   EXPECT_TRUE(!reg.IsNoRegister());
-  EXPECT_TRUE(!reg.IsCoreRegister());
+  EXPECT_TRUE(!reg.IsXRegister());
   EXPECT_TRUE(!reg.IsWRegister());
   EXPECT_TRUE(reg.IsDRegister());
   EXPECT_TRUE(!reg.IsSRegister());
   EXPECT_TRUE(reg.Overlaps(sreg));
   EXPECT_EQ(D31, reg.AsDRegister());
-  EXPECT_EQ(S31, reg.AsOverlappingDRegisterLow());
+  EXPECT_EQ(S31, reg.AsOverlappingSRegister());
   EXPECT_TRUE(reg.Equals(Arm64ManagedRegister::FromDRegister(D31)));
 }
 
@@ -220,101 +219,90 @@
   Arm64ManagedRegister reg = Arm64ManagedRegister::FromSRegister(S0);
   Arm64ManagedRegister dreg = Arm64ManagedRegister::FromDRegister(D0);
   EXPECT_TRUE(!reg.IsNoRegister());
-  EXPECT_TRUE(!reg.IsCoreRegister());
+  EXPECT_TRUE(!reg.IsXRegister());
   EXPECT_TRUE(!reg.IsWRegister());
   EXPECT_TRUE(reg.IsSRegister());
   EXPECT_TRUE(!reg.IsDRegister());
   EXPECT_TRUE(reg.Overlaps(dreg));
   EXPECT_EQ(S0, reg.AsSRegister());
-  EXPECT_EQ(D0, reg.AsOverlappingSRegisterD());
+  EXPECT_EQ(D0, reg.AsOverlappingDRegister());
   EXPECT_TRUE(reg.Equals(Arm64ManagedRegister::FromSRegister(S0)));
 
   reg = Arm64ManagedRegister::FromSRegister(S5);
   dreg = Arm64ManagedRegister::FromDRegister(D5);
   EXPECT_TRUE(!reg.IsNoRegister());
-  EXPECT_TRUE(!reg.IsCoreRegister());
+  EXPECT_TRUE(!reg.IsXRegister());
   EXPECT_TRUE(!reg.IsWRegister());
   EXPECT_TRUE(reg.IsSRegister());
   EXPECT_TRUE(!reg.IsDRegister());
   EXPECT_TRUE(reg.Overlaps(dreg));
   EXPECT_EQ(S5, reg.AsSRegister());
-  EXPECT_EQ(D5, reg.AsOverlappingSRegisterD());
+  EXPECT_EQ(D5, reg.AsOverlappingDRegister());
   EXPECT_TRUE(reg.Equals(Arm64ManagedRegister::FromSRegister(S5)));
 
   reg = Arm64ManagedRegister::FromSRegister(S7);
   dreg = Arm64ManagedRegister::FromDRegister(D7);
   EXPECT_TRUE(!reg.IsNoRegister());
-  EXPECT_TRUE(!reg.IsCoreRegister());
+  EXPECT_TRUE(!reg.IsXRegister());
   EXPECT_TRUE(!reg.IsWRegister());
   EXPECT_TRUE(reg.IsSRegister());
   EXPECT_TRUE(!reg.IsDRegister());
   EXPECT_TRUE(reg.Overlaps(dreg));
   EXPECT_EQ(S7, reg.AsSRegister());
-  EXPECT_EQ(D7, reg.AsOverlappingSRegisterD());
+  EXPECT_EQ(D7, reg.AsOverlappingDRegister());
   EXPECT_TRUE(reg.Equals(Arm64ManagedRegister::FromSRegister(S7)));
 
   reg = Arm64ManagedRegister::FromSRegister(S31);
   dreg = Arm64ManagedRegister::FromDRegister(D31);
   EXPECT_TRUE(!reg.IsNoRegister());
-  EXPECT_TRUE(!reg.IsCoreRegister());
+  EXPECT_TRUE(!reg.IsXRegister());
   EXPECT_TRUE(!reg.IsWRegister());
   EXPECT_TRUE(reg.IsSRegister());
   EXPECT_TRUE(!reg.IsDRegister());
   EXPECT_TRUE(reg.Overlaps(dreg));
   EXPECT_EQ(S31, reg.AsSRegister());
-  EXPECT_EQ(D31, reg.AsOverlappingSRegisterD());
+  EXPECT_EQ(D31, reg.AsOverlappingDRegister());
   EXPECT_TRUE(reg.Equals(Arm64ManagedRegister::FromSRegister(S31)));
 }
 
 TEST(Arm64ManagedRegister, Equals) {
   ManagedRegister no_reg = ManagedRegister::NoRegister();
   EXPECT_TRUE(no_reg.Equals(Arm64ManagedRegister::NoRegister()));
-  EXPECT_TRUE(!no_reg.Equals(Arm64ManagedRegister::FromCoreRegister(X0)));
-  EXPECT_TRUE(!no_reg.Equals(Arm64ManagedRegister::FromCoreRegister(X1)));
+  EXPECT_TRUE(!no_reg.Equals(Arm64ManagedRegister::FromXRegister(X0)));
+  EXPECT_TRUE(!no_reg.Equals(Arm64ManagedRegister::FromXRegister(X1)));
   EXPECT_TRUE(!no_reg.Equals(Arm64ManagedRegister::FromWRegister(W0)));
   EXPECT_TRUE(!no_reg.Equals(Arm64ManagedRegister::FromWRegister(W1)));
   EXPECT_TRUE(!no_reg.Equals(Arm64ManagedRegister::FromDRegister(D0)));
   EXPECT_TRUE(!no_reg.Equals(Arm64ManagedRegister::FromSRegister(S0)));
 
-  Arm64ManagedRegister reg_X0 = Arm64ManagedRegister::FromCoreRegister(X0);
+  Arm64ManagedRegister reg_X0 = Arm64ManagedRegister::FromXRegister(X0);
   EXPECT_TRUE(!reg_X0.Equals(Arm64ManagedRegister::NoRegister()));
-  EXPECT_TRUE(reg_X0.Equals(Arm64ManagedRegister::FromCoreRegister(X0)));
-  EXPECT_TRUE(!reg_X0.Equals(Arm64ManagedRegister::FromCoreRegister(X1)));
+  EXPECT_TRUE(reg_X0.Equals(Arm64ManagedRegister::FromXRegister(X0)));
+  EXPECT_TRUE(!reg_X0.Equals(Arm64ManagedRegister::FromXRegister(X1)));
   EXPECT_TRUE(!reg_X0.Equals(Arm64ManagedRegister::FromWRegister(W0)));
   EXPECT_TRUE(!reg_X0.Equals(Arm64ManagedRegister::FromSRegister(S0)));
   EXPECT_TRUE(!reg_X0.Equals(Arm64ManagedRegister::FromDRegister(D0)));
 
-  Arm64ManagedRegister reg_X1 = Arm64ManagedRegister::FromCoreRegister(X1);
+  Arm64ManagedRegister reg_X1 = Arm64ManagedRegister::FromXRegister(X1);
   EXPECT_TRUE(!reg_X1.Equals(Arm64ManagedRegister::NoRegister()));
-  EXPECT_TRUE(!reg_X1.Equals(Arm64ManagedRegister::FromCoreRegister(X0)));
-  EXPECT_TRUE(reg_X1.Equals(Arm64ManagedRegister::FromCoreRegister(X1)));
+  EXPECT_TRUE(!reg_X1.Equals(Arm64ManagedRegister::FromXRegister(X0)));
+  EXPECT_TRUE(reg_X1.Equals(Arm64ManagedRegister::FromXRegister(X1)));
   EXPECT_TRUE(!reg_X1.Equals(Arm64ManagedRegister::FromWRegister(W1)));
   EXPECT_TRUE(!reg_X1.Equals(Arm64ManagedRegister::FromDRegister(D0)));
   EXPECT_TRUE(!reg_X1.Equals(Arm64ManagedRegister::FromSRegister(S0)));
   EXPECT_TRUE(!reg_X1.Equals(Arm64ManagedRegister::FromDRegister(D1)));
   EXPECT_TRUE(!reg_X1.Equals(Arm64ManagedRegister::FromSRegister(S1)));
 
-  Arm64ManagedRegister reg_X31 = Arm64ManagedRegister::FromCoreRegister(X31);
-  EXPECT_TRUE(!reg_X31.Equals(Arm64ManagedRegister::NoRegister()));
-  EXPECT_TRUE(reg_X31.Equals(Arm64ManagedRegister::FromCoreRegister(SP)));
-  EXPECT_TRUE(!reg_X31.Equals(Arm64ManagedRegister::FromCoreRegister(XZR)));
-  EXPECT_TRUE(!reg_X31.Equals(Arm64ManagedRegister::FromWRegister(W31)));
-  EXPECT_TRUE(!reg_X31.Equals(Arm64ManagedRegister::FromWRegister(WZR)));
-  EXPECT_TRUE(!reg_X31.Equals(Arm64ManagedRegister::FromSRegister(S0)));
-  EXPECT_TRUE(!reg_X31.Equals(Arm64ManagedRegister::FromDRegister(D0)));
-
-  Arm64ManagedRegister reg_SP = Arm64ManagedRegister::FromCoreRegister(SP);
+  Arm64ManagedRegister reg_SP = Arm64ManagedRegister::FromXRegister(SP);
   EXPECT_TRUE(!reg_SP.Equals(Arm64ManagedRegister::NoRegister()));
-  EXPECT_TRUE(reg_SP.Equals(Arm64ManagedRegister::FromCoreRegister(X31)));
-  EXPECT_TRUE(!reg_SP.Equals(Arm64ManagedRegister::FromCoreRegister(XZR)));
-  EXPECT_TRUE(!reg_SP.Equals(Arm64ManagedRegister::FromWRegister(W31)));
+  EXPECT_TRUE(!reg_SP.Equals(Arm64ManagedRegister::FromXRegister(XZR)));
   EXPECT_TRUE(!reg_SP.Equals(Arm64ManagedRegister::FromSRegister(S0)));
   EXPECT_TRUE(!reg_SP.Equals(Arm64ManagedRegister::FromDRegister(D0)));
 
   Arm64ManagedRegister reg_W8 = Arm64ManagedRegister::FromWRegister(W8);
   EXPECT_TRUE(!reg_W8.Equals(Arm64ManagedRegister::NoRegister()));
-  EXPECT_TRUE(!reg_W8.Equals(Arm64ManagedRegister::FromCoreRegister(X0)));
-  EXPECT_TRUE(!reg_W8.Equals(Arm64ManagedRegister::FromCoreRegister(X8)));
+  EXPECT_TRUE(!reg_W8.Equals(Arm64ManagedRegister::FromXRegister(X0)));
+  EXPECT_TRUE(!reg_W8.Equals(Arm64ManagedRegister::FromXRegister(X8)));
   EXPECT_TRUE(reg_W8.Equals(Arm64ManagedRegister::FromWRegister(W8)));
   EXPECT_TRUE(!reg_W8.Equals(Arm64ManagedRegister::FromDRegister(D0)));
   EXPECT_TRUE(!reg_W8.Equals(Arm64ManagedRegister::FromSRegister(S0)));
@@ -323,8 +311,8 @@
 
   Arm64ManagedRegister reg_W12 = Arm64ManagedRegister::FromWRegister(W12);
   EXPECT_TRUE(!reg_W12.Equals(Arm64ManagedRegister::NoRegister()));
-  EXPECT_TRUE(!reg_W12.Equals(Arm64ManagedRegister::FromCoreRegister(X0)));
-  EXPECT_TRUE(!reg_W12.Equals(Arm64ManagedRegister::FromCoreRegister(X8)));
+  EXPECT_TRUE(!reg_W12.Equals(Arm64ManagedRegister::FromXRegister(X0)));
+  EXPECT_TRUE(!reg_W12.Equals(Arm64ManagedRegister::FromXRegister(X8)));
   EXPECT_TRUE(reg_W12.Equals(Arm64ManagedRegister::FromWRegister(W12)));
   EXPECT_TRUE(!reg_W12.Equals(Arm64ManagedRegister::FromDRegister(D0)));
   EXPECT_TRUE(!reg_W12.Equals(Arm64ManagedRegister::FromSRegister(S0)));
@@ -333,8 +321,8 @@
 
   Arm64ManagedRegister reg_S0 = Arm64ManagedRegister::FromSRegister(S0);
   EXPECT_TRUE(!reg_S0.Equals(Arm64ManagedRegister::NoRegister()));
-  EXPECT_TRUE(!reg_S0.Equals(Arm64ManagedRegister::FromCoreRegister(X0)));
-  EXPECT_TRUE(!reg_S0.Equals(Arm64ManagedRegister::FromCoreRegister(X1)));
+  EXPECT_TRUE(!reg_S0.Equals(Arm64ManagedRegister::FromXRegister(X0)));
+  EXPECT_TRUE(!reg_S0.Equals(Arm64ManagedRegister::FromXRegister(X1)));
   EXPECT_TRUE(!reg_S0.Equals(Arm64ManagedRegister::FromWRegister(W0)));
   EXPECT_TRUE(reg_S0.Equals(Arm64ManagedRegister::FromSRegister(S0)));
   EXPECT_TRUE(!reg_S0.Equals(Arm64ManagedRegister::FromSRegister(S1)));
@@ -343,8 +331,8 @@
 
   Arm64ManagedRegister reg_S1 = Arm64ManagedRegister::FromSRegister(S1);
   EXPECT_TRUE(!reg_S1.Equals(Arm64ManagedRegister::NoRegister()));
-  EXPECT_TRUE(!reg_S1.Equals(Arm64ManagedRegister::FromCoreRegister(X0)));
-  EXPECT_TRUE(!reg_S1.Equals(Arm64ManagedRegister::FromCoreRegister(X1)));
+  EXPECT_TRUE(!reg_S1.Equals(Arm64ManagedRegister::FromXRegister(X0)));
+  EXPECT_TRUE(!reg_S1.Equals(Arm64ManagedRegister::FromXRegister(X1)));
   EXPECT_TRUE(!reg_S1.Equals(Arm64ManagedRegister::FromWRegister(W0)));
   EXPECT_TRUE(!reg_S1.Equals(Arm64ManagedRegister::FromSRegister(S0)));
   EXPECT_TRUE(reg_S1.Equals(Arm64ManagedRegister::FromSRegister(S1)));
@@ -353,8 +341,8 @@
 
   Arm64ManagedRegister reg_S31 = Arm64ManagedRegister::FromSRegister(S31);
   EXPECT_TRUE(!reg_S31.Equals(Arm64ManagedRegister::NoRegister()));
-  EXPECT_TRUE(!reg_S31.Equals(Arm64ManagedRegister::FromCoreRegister(X0)));
-  EXPECT_TRUE(!reg_S31.Equals(Arm64ManagedRegister::FromCoreRegister(X1)));
+  EXPECT_TRUE(!reg_S31.Equals(Arm64ManagedRegister::FromXRegister(X0)));
+  EXPECT_TRUE(!reg_S31.Equals(Arm64ManagedRegister::FromXRegister(X1)));
   EXPECT_TRUE(!reg_S31.Equals(Arm64ManagedRegister::FromWRegister(W0)));
   EXPECT_TRUE(!reg_S31.Equals(Arm64ManagedRegister::FromSRegister(S0)));
   EXPECT_TRUE(reg_S31.Equals(Arm64ManagedRegister::FromSRegister(S31)));
@@ -363,7 +351,7 @@
 
   Arm64ManagedRegister reg_D0 = Arm64ManagedRegister::FromDRegister(D0);
   EXPECT_TRUE(!reg_D0.Equals(Arm64ManagedRegister::NoRegister()));
-  EXPECT_TRUE(!reg_D0.Equals(Arm64ManagedRegister::FromCoreRegister(X0)));
+  EXPECT_TRUE(!reg_D0.Equals(Arm64ManagedRegister::FromXRegister(X0)));
   EXPECT_TRUE(!reg_D0.Equals(Arm64ManagedRegister::FromWRegister(W1)));
   EXPECT_TRUE(!reg_D0.Equals(Arm64ManagedRegister::FromSRegister(S0)));
   EXPECT_TRUE(!reg_D0.Equals(Arm64ManagedRegister::FromSRegister(S0)));
@@ -373,8 +361,8 @@
 
   Arm64ManagedRegister reg_D15 = Arm64ManagedRegister::FromDRegister(D15);
   EXPECT_TRUE(!reg_D15.Equals(Arm64ManagedRegister::NoRegister()));
-  EXPECT_TRUE(!reg_D15.Equals(Arm64ManagedRegister::FromCoreRegister(X0)));
-  EXPECT_TRUE(!reg_D15.Equals(Arm64ManagedRegister::FromCoreRegister(X1)));
+  EXPECT_TRUE(!reg_D15.Equals(Arm64ManagedRegister::FromXRegister(X0)));
+  EXPECT_TRUE(!reg_D15.Equals(Arm64ManagedRegister::FromXRegister(X1)));
   EXPECT_TRUE(!reg_D15.Equals(Arm64ManagedRegister::FromWRegister(W0)));
   EXPECT_TRUE(!reg_D15.Equals(Arm64ManagedRegister::FromSRegister(S0)));
   EXPECT_TRUE(!reg_D15.Equals(Arm64ManagedRegister::FromSRegister(S31)));
@@ -384,17 +372,17 @@
 }
 
 TEST(Arm64ManagedRegister, Overlaps) {
-  Arm64ManagedRegister reg = Arm64ManagedRegister::FromCoreRegister(X0);
+  Arm64ManagedRegister reg = Arm64ManagedRegister::FromXRegister(X0);
   Arm64ManagedRegister reg_o = Arm64ManagedRegister::FromWRegister(W0);
-  EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X0)));
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X1)));
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(SP)));
+  EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromXRegister(X0)));
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromXRegister(X1)));
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromXRegister(SP)));
   EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromWRegister(W0)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W1)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W12)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(WZR)));
-  EXPECT_EQ(X0, reg_o.AsOverlappingWRegisterCore());
-  EXPECT_EQ(W0, reg.AsOverlappingCoreRegisterLow());
+  EXPECT_EQ(X0, reg_o.AsOverlappingXRegister());
+  EXPECT_EQ(W0, reg.AsOverlappingWRegister());
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S0)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S1)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S2)));
@@ -406,17 +394,17 @@
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromDRegister(D7)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromDRegister(D15)));
 
-  reg = Arm64ManagedRegister::FromCoreRegister(X10);
+  reg = Arm64ManagedRegister::FromXRegister(X10);
   reg_o = Arm64ManagedRegister::FromWRegister(W10);
-  EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X10)));
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X1)));
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(SP)));
+  EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromXRegister(X10)));
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromXRegister(X1)));
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromXRegister(SP)));
   EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromWRegister(W10)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W1)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W12)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(WZR)));
-  EXPECT_EQ(X10, reg_o.AsOverlappingWRegisterCore());
-  EXPECT_EQ(W10, reg.AsOverlappingCoreRegisterLow());
+  EXPECT_EQ(X10, reg_o.AsOverlappingXRegister());
+  EXPECT_EQ(W10, reg.AsOverlappingWRegister());
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S0)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S1)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S2)));
@@ -428,17 +416,17 @@
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromDRegister(D7)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromDRegister(D15)));
 
-  reg = Arm64ManagedRegister::FromCoreRegister(IP1);
+  reg = Arm64ManagedRegister::FromXRegister(IP1);
   reg_o = Arm64ManagedRegister::FromWRegister(W17);
-  EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X17)));
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X1)));
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(SP)));
+  EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromXRegister(X17)));
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromXRegister(X1)));
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromXRegister(SP)));
   EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromWRegister(W17)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W1)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W12)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(WZR)));
-  EXPECT_EQ(X17, reg_o.AsOverlappingWRegisterCore());
-  EXPECT_EQ(W17, reg.AsOverlappingCoreRegisterLow());
+  EXPECT_EQ(X17, reg_o.AsOverlappingXRegister());
+  EXPECT_EQ(W17, reg.AsOverlappingWRegister());
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S0)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S1)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S2)));
@@ -450,19 +438,15 @@
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromDRegister(D7)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromDRegister(D15)));
 
-  reg = Arm64ManagedRegister::FromCoreRegister(XZR);
+  reg = Arm64ManagedRegister::FromXRegister(XZR);
   reg_o = Arm64ManagedRegister::FromWRegister(WZR);
-  EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X31)));
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X1)));
-  EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(SP)));
-  EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromWRegister(W31)));
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromXRegister(X1)));
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromXRegister(SP)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W1)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W12)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W19)));
-  EXPECT_EQ(X31, reg_o.AsOverlappingWRegisterCore());
-  EXPECT_EQ(SP, reg_o.AsOverlappingWRegisterCore());
-  EXPECT_NE(XZR, reg_o.AsOverlappingWRegisterCore());
-  EXPECT_EQ(W31, reg.AsOverlappingCoreRegisterLow());
+  EXPECT_NE(SP, reg_o.AsOverlappingXRegister());
+  EXPECT_EQ(XZR, reg_o.AsOverlappingXRegister());
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S0)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S1)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S2)));
@@ -474,17 +458,13 @@
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromDRegister(D7)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromDRegister(D15)));
 
-  reg = Arm64ManagedRegister::FromCoreRegister(SP);
+  reg = Arm64ManagedRegister::FromXRegister(SP);
   reg_o = Arm64ManagedRegister::FromWRegister(WZR);
-  EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X31)));
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X1)));
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X15)));
-  EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromWRegister(WZR)));
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromXRegister(X1)));
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromXRegister(X15)));
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(WZR)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W1)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W12)));
-  EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromWRegister(W31)));
-  EXPECT_EQ(X31, reg_o.AsOverlappingWRegisterCore());
-  EXPECT_EQ(W31, reg.AsOverlappingCoreRegisterLow());
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S0)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S1)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S2)));
@@ -497,15 +477,15 @@
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromDRegister(D15)));
 
   reg = Arm64ManagedRegister::FromWRegister(W1);
-  reg_o = Arm64ManagedRegister::FromCoreRegister(X1);
+  reg_o = Arm64ManagedRegister::FromXRegister(X1);
   EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromWRegister(W1)));
-  EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X1)));
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X15)));
+  EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromXRegister(X1)));
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromXRegister(X15)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(WZR)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W12)));
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W31)));
-  EXPECT_EQ(W1, reg_o.AsOverlappingCoreRegisterLow());
-  EXPECT_EQ(X1, reg.AsOverlappingWRegisterCore());
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W30)));
+  EXPECT_EQ(W1, reg_o.AsOverlappingWRegister());
+  EXPECT_EQ(X1, reg.AsOverlappingXRegister());
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S0)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S1)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S2)));
@@ -518,15 +498,15 @@
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromDRegister(D15)));
 
   reg = Arm64ManagedRegister::FromWRegister(W21);
-  reg_o = Arm64ManagedRegister::FromCoreRegister(X21);
+  reg_o = Arm64ManagedRegister::FromXRegister(X21);
   EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromWRegister(W21)));
-  EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X21)));
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X15)));
+  EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromXRegister(X21)));
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromXRegister(X15)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(WZR)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W12)));
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W31)));
-  EXPECT_EQ(W21, reg_o.AsOverlappingCoreRegisterLow());
-  EXPECT_EQ(X21, reg.AsOverlappingWRegisterCore());
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W30)));
+  EXPECT_EQ(W21, reg_o.AsOverlappingWRegister());
+  EXPECT_EQ(X21, reg.AsOverlappingXRegister());
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S0)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S1)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S2)));
@@ -541,15 +521,15 @@
 
   reg = Arm64ManagedRegister::FromSRegister(S1);
   reg_o = Arm64ManagedRegister::FromDRegister(D1);
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X31)));
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X1)));
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X15)));
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromXRegister(X30)));
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromXRegister(X1)));
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromXRegister(X15)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(WZR)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W1)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W12)));
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W31)));
-  EXPECT_EQ(S1, reg_o.AsOverlappingDRegisterLow());
-  EXPECT_EQ(D1, reg.AsOverlappingSRegisterD());
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W30)));
+  EXPECT_EQ(S1, reg_o.AsOverlappingSRegister());
+  EXPECT_EQ(D1, reg.AsOverlappingDRegister());
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S0)));
   EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromSRegister(S1)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S2)));
@@ -564,15 +544,15 @@
 
   reg = Arm64ManagedRegister::FromSRegister(S15);
   reg_o = Arm64ManagedRegister::FromDRegister(D15);
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X31)));
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X1)));
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X15)));
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromXRegister(X30)));
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromXRegister(X1)));
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromXRegister(X15)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(WZR)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W1)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W12)));
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W31)));
-  EXPECT_EQ(S15, reg_o.AsOverlappingDRegisterLow());
-  EXPECT_EQ(D15, reg.AsOverlappingSRegisterD());
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W30)));
+  EXPECT_EQ(S15, reg_o.AsOverlappingSRegister());
+  EXPECT_EQ(D15, reg.AsOverlappingDRegister());
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S0)));
   EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromSRegister(S15)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S2)));
@@ -587,15 +567,15 @@
 
   reg = Arm64ManagedRegister::FromDRegister(D15);
   reg_o = Arm64ManagedRegister::FromSRegister(S15);
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X31)));
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X1)));
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromCoreRegister(X15)));
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromXRegister(X30)));
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromXRegister(X1)));
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromXRegister(X15)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(WZR)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W1)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W12)));
-  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W31)));
-  EXPECT_EQ(S15, reg.AsOverlappingDRegisterLow());
-  EXPECT_EQ(D15, reg_o.AsOverlappingSRegisterD());
+  EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromWRegister(W30)));
+  EXPECT_EQ(S15, reg.AsOverlappingSRegister());
+  EXPECT_EQ(D15, reg_o.AsOverlappingDRegister());
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S0)));
   EXPECT_TRUE(reg.Overlaps(Arm64ManagedRegister::FromSRegister(S15)));
   EXPECT_TRUE(!reg.Overlaps(Arm64ManagedRegister::FromSRegister(S2)));
@@ -642,9 +622,6 @@
   EXPECT_TRUE(vixl::x28.Is(Arm64Assembler::reg_x(X28)));
   EXPECT_TRUE(vixl::x29.Is(Arm64Assembler::reg_x(X29)));
   EXPECT_TRUE(vixl::x30.Is(Arm64Assembler::reg_x(X30)));
-  // FIXME: Take a look here.
-  EXPECT_TRUE(vixl::sp.Is(Arm64Assembler::reg_x(X31)));
-  EXPECT_TRUE(!vixl::x31.Is(Arm64Assembler::reg_x(X31)));
 
   EXPECT_TRUE(vixl::x18.Is(Arm64Assembler::reg_x(TR)));
   EXPECT_TRUE(vixl::ip0.Is(Arm64Assembler::reg_x(IP0)));
@@ -686,8 +663,9 @@
   EXPECT_TRUE(vixl::w28.Is(Arm64Assembler::reg_w(W28)));
   EXPECT_TRUE(vixl::w29.Is(Arm64Assembler::reg_w(W29)));
   EXPECT_TRUE(vixl::w30.Is(Arm64Assembler::reg_w(W30)));
-  EXPECT_TRUE(vixl::w31.Is(Arm64Assembler::reg_w(W31)));
+  EXPECT_TRUE(vixl::w31.Is(Arm64Assembler::reg_w(WZR)));
   EXPECT_TRUE(vixl::wzr.Is(Arm64Assembler::reg_w(WZR)));
+  EXPECT_TRUE(vixl::wsp.Is(Arm64Assembler::reg_w(WSP)));
 
   // D Registers.
   EXPECT_TRUE(vixl::d0.Is(Arm64Assembler::reg_d(D0)));
diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h
index 91b8d8a..2b0c94c 100644
--- a/compiler/utils/assembler.h
+++ b/compiler/utils/assembler.h
@@ -118,6 +118,7 @@
   friend class arm::ArmAssembler;
   friend class arm::Arm32Assembler;
   friend class arm::Thumb2Assembler;
+  friend class arm64::Arm64Assembler;
   friend class mips::MipsAssembler;
   friend class x86::X86Assembler;
   friend class x86_64::X86_64Assembler;
diff --git a/compiler/utils/assembler_test.h b/compiler/utils/assembler_test.h
index 3742913..91237ae 100644
--- a/compiler/utils/assembler_test.h
+++ b/compiler/utils/assembler_test.h
@@ -24,7 +24,6 @@
 #include <cstdio>
 #include <cstdlib>
 #include <fstream>
-#include <iostream>
 #include <iterator>
 #include <sys/stat.h>
 
@@ -118,9 +117,8 @@
     std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
     for (auto reg : registers) {
       for (int64_t imm : imms) {
-        Imm* new_imm = CreateImmediate(imm);
-        (assembler_.get()->*f)(*reg, *new_imm);
-        delete new_imm;
+        Imm new_imm = CreateImmediate(imm);
+        (assembler_.get()->*f)(*reg, new_imm);
         std::string base = fmt;
 
         size_t reg_index = base.find("{reg}");
@@ -154,9 +152,8 @@
     std::string str;
     std::vector<int64_t> imms = CreateImmediateValues(imm_bytes);
     for (int64_t imm : imms) {
-      Imm* new_imm = CreateImmediate(imm);
-      (assembler_.get()->*f)(*new_imm);
-      delete new_imm;
+      Imm new_imm = CreateImmediate(imm);
+      (assembler_.get()->*f)(new_imm);
       std::string base = fmt;
 
       size_t imm_index = base.find("{imm}");
@@ -333,7 +330,7 @@
   }
 
   // Create an immediate from the specific value.
-  virtual Imm* CreateImmediate(int64_t imm_value) = 0;
+  virtual Imm CreateImmediate(int64_t imm_value) = 0;
 
  private:
   // Driver() assembles and compares the results. If the results are not equal and we have a
@@ -373,7 +370,7 @@
         }
       } else {
         // This will output the assembly.
-        EXPECT_EQ(*data, *res.code) << "Outputs (and disassembly) not identical.";
+        EXPECT_EQ(*res.code, *data) << "Outputs (and disassembly) not identical.";
       }
     }
   }
diff --git a/compiler/utils/scoped_arena_allocator.cc b/compiler/utils/scoped_arena_allocator.cc
index aeb2f76..2616150 100644
--- a/compiler/utils/scoped_arena_allocator.cc
+++ b/compiler/utils/scoped_arena_allocator.cc
@@ -115,10 +115,18 @@
 }
 
 ScopedArenaAllocator::~ScopedArenaAllocator() {
-  Reset();
+  DoReset();
 }
 
 void ScopedArenaAllocator::Reset() {
+  DoReset();
+  // If this allocator was Create()d, we need to move the arena_stack_->top_ptr_ past *this.
+  if (mark_ptr_ == reinterpret_cast<uint8_t*>(this)) {
+    arena_stack_->top_ptr_ = mark_ptr_ + RoundUp(sizeof(ScopedArenaAllocator), 8);
+  }
+}
+
+void ScopedArenaAllocator::DoReset() {
   DebugStackReference::CheckTop();
   DebugStackRefCounter::CheckNoRefs();
   arena_stack_->UpdatePeakStatsAndRestore(*this);
diff --git a/compiler/utils/scoped_arena_allocator.h b/compiler/utils/scoped_arena_allocator.h
index 62ea330..523f158 100644
--- a/compiler/utils/scoped_arena_allocator.h
+++ b/compiler/utils/scoped_arena_allocator.h
@@ -132,6 +132,8 @@
   uint8_t* mark_ptr_;
   uint8_t* mark_end_;
 
+  void DoReset();
+
   template <typename T>
   friend class ScopedArenaAllocatorAdapter;
 
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index c7eada3..b5bf31b 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -29,7 +29,7 @@
 namespace art {
 namespace x86 {
 
-class Immediate {
+class Immediate : public ValueObject {
  public:
   explicit Immediate(int32_t value) : value_(value) {}
 
@@ -47,7 +47,7 @@
 };
 
 
-class Operand {
+class Operand : public ValueObject {
  public:
   uint8_t mod() const {
     return (encoding_at(0) >> 6) & 3;
@@ -129,8 +129,6 @@
   }
 
   friend class X86Assembler;
-
-  DISALLOW_COPY_AND_ASSIGN(Operand);
 };
 
 
@@ -168,7 +166,6 @@
     }
   }
 
-
   Address(Register index, ScaleFactor scale, int32_t disp) {
     CHECK_NE(index, ESP);  // Illegal addressing mode.
     SetModRM(0, ESP);
@@ -205,14 +202,12 @@
 
  private:
   Address() {}
-
-  DISALLOW_COPY_AND_ASSIGN(Address);
 };
 
 
 class X86Assembler FINAL : public Assembler {
  public:
-  explicit X86Assembler() {}
+  explicit X86Assembler() : cfi_cfa_offset_(0), cfi_pc_(0) {}
   virtual ~X86Assembler() {}
 
   /*
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 75823e3..f4c9862 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -317,7 +317,7 @@
   EmitOptionalRex32(dst, src);
   EmitUint8(0x0F);
   EmitUint8(0x28);
-  EmitXmmRegisterOperand(src.LowBits(), dst);
+  EmitXmmRegisterOperand(dst.LowBits(), src);
 }
 
 
@@ -354,7 +354,7 @@
 void X86_64Assembler::movd(XmmRegister dst, CpuRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0x66);
-  EmitOptionalRex32(dst, src);
+  EmitRex64(dst, src);
   EmitUint8(0x0F);
   EmitUint8(0x6E);
   EmitOperand(dst.LowBits(), Operand(src));
@@ -364,7 +364,7 @@
 void X86_64Assembler::movd(CpuRegister dst, XmmRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0x66);
-  EmitOptionalRex32(src, dst);
+  EmitRex64(src, dst);
   EmitUint8(0x0F);
   EmitUint8(0x7E);
   EmitOperand(src.LowBits(), Operand(dst));
@@ -1238,6 +1238,34 @@
 }
 
 
+void X86_64Assembler::imulq(CpuRegister dst, CpuRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitRex64(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0xAF);
+  EmitRegisterOperand(dst.LowBits(), src.LowBits());
+}
+
+
+void X86_64Assembler::imulq(CpuRegister reg, const Immediate& imm) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  CHECK(imm.is_int32());  // imulq only supports 32b immediate.
+  EmitRex64(reg);
+  EmitUint8(0x69);
+  EmitOperand(reg.LowBits(), Operand(reg));
+  EmitImmediate(imm);
+}
+
+
+void X86_64Assembler::imulq(CpuRegister reg, const Address& address) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitRex64(reg, address);
+  EmitUint8(0x0F);
+  EmitUint8(0xAF);
+  EmitOperand(reg.LowBits(), address);
+}
+
+
 void X86_64Assembler::imull(CpuRegister reg) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitOptionalRex32(reg);
@@ -1270,7 +1298,6 @@
 }
 
 
-
 void X86_64Assembler::shll(CpuRegister reg, const Immediate& imm) {
   EmitGenericShift(false, 4, reg, imm);
 }
@@ -1721,6 +1748,10 @@
   EmitOptionalRex(false, true, dst.NeedsRex(), false, src.NeedsRex());
 }
 
+void X86_64Assembler::EmitRex64(XmmRegister dst, CpuRegister src) {
+  EmitOptionalRex(false, true, dst.NeedsRex(), false, src.NeedsRex());
+}
+
 void X86_64Assembler::EmitRex64(CpuRegister dst, const Operand& operand) {
   uint8_t rex = 0x48 | operand.rex();  // REX.W000
   if (dst.NeedsRex()) {
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index 1d9eba4..92b81ec 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -36,7 +36,7 @@
 //
 // Note: As we support cross-compilation, the value type must be int64_t. Please be aware of
 // conversion rules in expressions regarding negation, especially size_t on 32b.
-class Immediate {
+class Immediate : public ValueObject {
  public:
   explicit Immediate(int64_t value) : value_(value) {}
 
@@ -54,12 +54,10 @@
 
  private:
   const int64_t value_;
-
-  DISALLOW_COPY_AND_ASSIGN(Immediate);
 };
 
 
-class Operand {
+class Operand : public ValueObject {
  public:
   uint8_t mod() const {
     return (encoding_at(0) >> 6) & 3;
@@ -157,8 +155,6 @@
   }
 
   friend class X86_64Assembler;
-
-  DISALLOW_COPY_AND_ASSIGN(Operand);
 };
 
 
@@ -247,8 +243,6 @@
 
  private:
   Address() {}
-
-  DISALLOW_COPY_AND_ASSIGN(Address);
 };
 
 
@@ -436,6 +430,10 @@
   void imull(CpuRegister reg, const Immediate& imm);
   void imull(CpuRegister reg, const Address& address);
 
+  void imulq(CpuRegister dst, CpuRegister src);
+  void imulq(CpuRegister reg, const Immediate& imm);
+  void imulq(CpuRegister reg, const Address& address);
+
   void imull(CpuRegister reg);
   void imull(const Address& address);
 
@@ -662,6 +660,7 @@
   void EmitRex64(CpuRegister reg);
   void EmitRex64(CpuRegister dst, CpuRegister src);
   void EmitRex64(CpuRegister dst, const Operand& operand);
+  void EmitRex64(XmmRegister dst, CpuRegister src);
 
   // Emit a REX prefix to normalize byte registers plus necessary register bit encodings.
   void EmitOptionalByteRegNormalizingRex32(CpuRegister dst, CpuRegister src);
@@ -688,7 +687,7 @@
 inline void X86_64Assembler::EmitRegisterOperand(uint8_t rm, uint8_t reg) {
   CHECK_GE(rm, 0);
   CHECK_LT(rm, 8);
-  buffer_.Emit<uint8_t>(0xC0 + (rm << 3) + reg);
+  buffer_.Emit<uint8_t>((0xC0 | (reg & 7)) + (rm << 3));
 }
 
 inline void X86_64Assembler::EmitXmmRegisterOperand(uint8_t rm, XmmRegister reg) {
diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc
index 7a48b63..18c5cbc 100644
--- a/compiler/utils/x86_64/assembler_x86_64_test.cc
+++ b/compiler/utils/x86_64/assembler_x86_64_test.cc
@@ -72,8 +72,8 @@
     return registers_;
   }
 
-  x86_64::Immediate* CreateImmediate(int64_t imm_value) OVERRIDE {
-    return new x86_64::Immediate(imm_value);
+  x86_64::Immediate CreateImmediate(int64_t imm_value) OVERRIDE {
+    return x86_64::Immediate(imm_value);
   }
 
  private:
@@ -112,6 +112,9 @@
   DriverStr(RepeatRI(&x86_64::X86_64Assembler::addq, 4U, "addq ${imm}, %{reg}"), "addqi");
 }
 
+TEST_F(AssemblerX86_64Test, ImulqRegs) {
+  DriverStr(RepeatRR(&x86_64::X86_64Assembler::imulq, "imulq %{reg2}, %{reg1}"), "imulq");
+}
 
 TEST_F(AssemblerX86_64Test, SubqRegs) {
   DriverStr(RepeatRR(&x86_64::X86_64Assembler::subq, "subq %{reg2}, %{reg1}"), "subq");
@@ -131,6 +134,32 @@
   DriverStr(RepeatRI(&x86_64::X86_64Assembler::xorq, 4U, "xorq ${imm}, %{reg}"), "xorqi");
 }
 
+TEST_F(AssemblerX86_64Test, Movaps) {
+  GetAssembler()->movaps(x86_64::XmmRegister(x86_64::XMM0), x86_64::XmmRegister(x86_64::XMM8));
+  DriverStr("movaps %xmm8, %xmm0", "movaps");
+}
+
+TEST_F(AssemblerX86_64Test, Movd) {
+  GetAssembler()->movd(x86_64::XmmRegister(x86_64::XMM0), x86_64::CpuRegister(x86_64::R11));
+  GetAssembler()->movd(x86_64::XmmRegister(x86_64::XMM0), x86_64::CpuRegister(x86_64::RAX));
+  GetAssembler()->movd(x86_64::XmmRegister(x86_64::XMM8), x86_64::CpuRegister(x86_64::R11));
+  GetAssembler()->movd(x86_64::XmmRegister(x86_64::XMM8), x86_64::CpuRegister(x86_64::RAX));
+  GetAssembler()->movd(x86_64::CpuRegister(x86_64::R11), x86_64::XmmRegister(x86_64::XMM0));
+  GetAssembler()->movd(x86_64::CpuRegister(x86_64::RAX), x86_64::XmmRegister(x86_64::XMM0));
+  GetAssembler()->movd(x86_64::CpuRegister(x86_64::R11), x86_64::XmmRegister(x86_64::XMM8));
+  GetAssembler()->movd(x86_64::CpuRegister(x86_64::RAX), x86_64::XmmRegister(x86_64::XMM8));
+  const char* expected =
+    "movd %r11, %xmm0\n"
+    "movd %rax, %xmm0\n"
+    "movd %r11, %xmm8\n"
+    "movd %rax, %xmm8\n"
+    "movd %xmm0, %r11\n"
+    "movd %xmm0, %rax\n"
+    "movd %xmm8, %r11\n"
+    "movd %xmm8, %rax\n";
+  DriverStr(expected, "movd");
+}
+
 TEST_F(AssemblerX86_64Test, Movl) {
   GetAssembler()->movl(x86_64::CpuRegister(x86_64::R8), x86_64::CpuRegister(x86_64::R11));
   GetAssembler()->movl(x86_64::CpuRegister(x86_64::RAX), x86_64::CpuRegister(x86_64::R11));
diff --git a/dalvikvm/Android.mk b/dalvikvm/Android.mk
index a06b5c5..0ef20d6 100644
--- a/dalvikvm/Android.mk
+++ b/dalvikvm/Android.mk
@@ -27,7 +27,9 @@
 LOCAL_SRC_FILES := dalvikvm.cc
 LOCAL_CFLAGS := $(dalvikvm_cflags)
 LOCAL_C_INCLUDES := art/runtime
-LOCAL_SHARED_LIBRARIES := libdl libnativehelper
+LOCAL_SHARED_LIBRARIES := libdl liblog libnativehelper
+LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
+LOCAL_LDFLAGS := -Wl,--version-script,art/sigchainlib/version-script.txt -Wl,--export-dynamic
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.common.mk
 LOCAL_MULTILIB := both
@@ -54,7 +56,12 @@
 LOCAL_CFLAGS := $(dalvikvm_cflags)
 LOCAL_C_INCLUDES := art/runtime
 LOCAL_SHARED_LIBRARIES := libnativehelper
+LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
 LOCAL_LDFLAGS := -ldl -lpthread
+# Mac OS linker doesn't understand --export-dynamic.
+ifneq ($(HOST_OS),darwin)
+  LOCAL_LDFLAGS += -Wl,--export-dynamic
+endif
 LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.common.mk
 LOCAL_IS_HOST_MODULE := true
diff --git a/dalvikvm/dalvikvm.cc b/dalvikvm/dalvikvm.cc
index 67794c8..7839aa8 100644
--- a/dalvikvm/dalvikvm.cc
+++ b/dalvikvm/dalvikvm.cc
@@ -152,7 +152,7 @@
   }
 
   if (curr_opt > option_count) {
-    fprintf(stderr, "curr_opt(%d) >= option_count(%d)\n", curr_opt, option_count);
+    fprintf(stderr, "curr_opt(%d) > option_count(%d)\n", curr_opt, option_count);
     abort();
     return EXIT_FAILURE;
   }
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index d782aeb..98712cd 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -30,6 +30,10 @@
 #include <sys/utsname.h>
 #endif
 
+#define ATRACE_TAG ATRACE_TAG_DALVIK
+#include "cutils/trace.h"
+
+#include "base/dumpable.h"
 #include "base/stl_util.h"
 #include "base/stringpiece.h"
 #include "base/timing_logger.h"
@@ -90,8 +94,7 @@
   va_end(ap);
 }
 
-static void Usage(const char* fmt, ...) NO_RETURN;
-static void Usage(const char* fmt, ...) {
+[[noreturn]] static void Usage(const char* fmt, ...) {
   va_list ap;
   va_start(ap, fmt);
   UsageErrorV(fmt, ap);
@@ -252,13 +255,23 @@
                      const CompilerOptions& compiler_options,
                      Compiler::Kind compiler_kind,
                      InstructionSet instruction_set,
-                     InstructionSetFeatures instruction_set_features,
+                     const InstructionSetFeatures* instruction_set_features,
                      VerificationResults* verification_results,
                      DexFileToMethodInlinerMap* method_inliner_map,
                      size_t thread_count)
       SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_) {
     CHECK(verification_results != nullptr);
     CHECK(method_inliner_map != nullptr);
+    if (instruction_set == kRuntimeISA) {
+      std::unique_ptr<const InstructionSetFeatures> runtime_features(
+          InstructionSetFeatures::FromCppDefines());
+      if (!instruction_set_features->Equals(runtime_features.get())) {
+        LOG(WARNING) << "Mismatch between dex2oat instruction set features ("
+            << *instruction_set_features << ") and those of dex2oat executable ("
+            << *runtime_features <<") for the command line:\n"
+            << CommandLine();
+      }
+    }
     std::unique_ptr<Dex2Oat> dex2oat(new Dex2Oat(&compiler_options,
                                                  compiler_kind,
                                                  instruction_set,
@@ -483,7 +496,7 @@
   explicit Dex2Oat(const CompilerOptions* compiler_options,
                    Compiler::Kind compiler_kind,
                    InstructionSet instruction_set,
-                   InstructionSetFeatures instruction_set_features,
+                   const InstructionSetFeatures* instruction_set_features,
                    VerificationResults* verification_results,
                    DexFileToMethodInlinerMap* method_inliner_map,
                    size_t thread_count)
@@ -528,7 +541,7 @@
   static void OpenClassPathFiles(const std::string& class_path,
                                  std::vector<const DexFile*>& dex_files) {
     std::vector<std::string> parsed;
-    Split(class_path, ':', parsed);
+    Split(class_path, ':', &parsed);
     // Take Locks::mutator_lock_ so that lock ordering on the ClassLinker::dex_lock_ is maintained.
     ScopedObjectAccess soa(Thread::Current());
     for (size_t i = 0; i < parsed.size(); ++i) {
@@ -557,7 +570,7 @@
   const Compiler::Kind compiler_kind_;
 
   const InstructionSet instruction_set_;
-  const InstructionSetFeatures instruction_set_features_;
+  const InstructionSetFeatures* const instruction_set_features_;
 
   VerificationResults* const verification_results_;
   DexFileToMethodInlinerMap* const method_inliner_map_;
@@ -663,7 +676,7 @@
     Message('W', message);
   }
 
-  static void Fatal(const std::string& message) NO_RETURN {
+  [[noreturn]] static void Fatal(const std::string& message) {
     Message('F', message);
     exit(1);
   }
@@ -729,38 +742,6 @@
 const unsigned int WatchDog::kWatchDogWarningSeconds;
 const unsigned int WatchDog::kWatchDogTimeoutSeconds;
 
-// Given a set of instruction features from the build, parse it.  The
-// input 'str' is a comma separated list of feature names.  Parse it and
-// return the InstructionSetFeatures object.
-static InstructionSetFeatures ParseFeatureList(std::string str) {
-  InstructionSetFeatures result;
-  typedef std::vector<std::string> FeatureList;
-  FeatureList features;
-  Split(str, ',', features);
-  for (FeatureList::iterator i = features.begin(); i != features.end(); i++) {
-    std::string feature = Trim(*i);
-    if (feature == "default") {
-      // Nothing to do.
-    } else if (feature == "div") {
-      // Supports divide instruction.
-       result.SetHasDivideInstruction(true);
-    } else if (feature == "nodiv") {
-      // Turn off support for divide instruction.
-      result.SetHasDivideInstruction(false);
-    } else if (feature == "lpae") {
-      // Supports Large Physical Address Extension.
-      result.SetHasLpae(true);
-    } else if (feature == "nolpae") {
-      // Turn off support for Large Physical Address Extension.
-      result.SetHasLpae(false);
-    } else {
-      Usage("Unknown instruction set feature: '%s'", feature.c_str());
-    }
-  }
-  // others...
-  return result;
-}
-
 void ParseStringAfterChar(const std::string& s, char c, std::string* parsed_value) {
   std::string::size_type colon = s.find(c);
   if (colon == std::string::npos) {
@@ -849,17 +830,20 @@
       ? Compiler::kPortable
       : Compiler::kQuick;
   const char* compiler_filter_string = nullptr;
+  bool compile_pic = false;
   int huge_method_threshold = CompilerOptions::kDefaultHugeMethodThreshold;
   int large_method_threshold = CompilerOptions::kDefaultLargeMethodThreshold;
   int small_method_threshold = CompilerOptions::kDefaultSmallMethodThreshold;
   int tiny_method_threshold = CompilerOptions::kDefaultTinyMethodThreshold;
   int num_dex_methods_threshold = CompilerOptions::kDefaultNumDexMethodsThreshold;
+  std::vector<std::string> verbose_methods;
 
-  // Take the default set of instruction features from the build.
-  InstructionSetFeatures instruction_set_features =
-      ParseFeatureList(Runtime::GetDefaultInstructionSetFeatures());
-
+  // Initialize ISA and ISA features to default values.
   InstructionSet instruction_set = kRuntimeISA;
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+      InstructionSetFeatures::FromFeatureString(kNone, "default", &error_msg));
+  CHECK(instruction_set_features.get() != nullptr) << error_msg;
 
   // Profile file to use
   std::string profile_file;
@@ -962,9 +946,20 @@
       } else if (instruction_set_str == "x86_64") {
         instruction_set = kX86_64;
       }
+    } else if (option.starts_with("--instruction-set-variant=")) {
+      StringPiece str = option.substr(strlen("--instruction-set-variant=")).data();
+      instruction_set_features.reset(
+          InstructionSetFeatures::FromVariant(instruction_set, str.as_string(), &error_msg));
+      if (instruction_set_features.get() == nullptr) {
+        Usage("%s", error_msg.c_str());
+      }
     } else if (option.starts_with("--instruction-set-features=")) {
       StringPiece str = option.substr(strlen("--instruction-set-features=")).data();
-      instruction_set_features = ParseFeatureList(str.as_string());
+      instruction_set_features.reset(
+          InstructionSetFeatures::FromFeatureString(instruction_set, str.as_string(), &error_msg));
+      if (instruction_set_features.get() == nullptr) {
+        Usage("%s", error_msg.c_str());
+      }
     } else if (option.starts_with("--compiler-backend=")) {
       StringPiece backend_str = option.substr(strlen("--compiler-backend=")).data();
       if (backend_str == "Quick") {
@@ -976,6 +971,8 @@
       }
     } else if (option.starts_with("--compiler-filter=")) {
       compiler_filter_string = option.substr(strlen("--compiler-filter=")).data();
+    } else if (option == "--compile-pic") {
+      compile_pic = true;
     } else if (option.starts_with("--huge-method-max=")) {
       const char* threshold = option.substr(strlen("--huge-method-max=")).data();
       if (!ParseInt(threshold, &huge_method_threshold)) {
@@ -1066,6 +1063,11 @@
       include_patch_information = true;
     } else if (option == "--no-include-patch-information") {
       include_patch_information = false;
+    } else if (option.starts_with("--verbose-methods=")) {
+      // TODO: rather than switch off compiler logging, make all VLOG(compiler) messages conditional
+      //       on having verbost methods.
+      gLogVerbosity.compiler = false;
+      Split(option.substr(strlen("--verbose-methods=")).ToString(), ',', &verbose_methods);
     } else {
       Usage("Unknown argument %s", option.data());
     }
@@ -1160,6 +1162,13 @@
     oat_unstripped += oat_filename;
   }
 
+  // If no instruction set feature was given, use the default one for the target
+  // instruction set.
+  if (instruction_set_features->GetInstructionSet() == kNone) {
+    instruction_set_features.reset(
+      InstructionSetFeatures::FromFeatureString(instruction_set, "default", &error_msg));
+  }
+
   if (compiler_filter_string == nullptr) {
     if (instruction_set == kMips64) {
       // TODO: fix compiler for Mips64.
@@ -1214,24 +1223,25 @@
     PassDriverMEOpts::PrintPassOptions();
   }
 
-  std::unique_ptr<CompilerOptions> compiler_options(new CompilerOptions(compiler_filter,
-                                                                        huge_method_threshold,
-                                                                        large_method_threshold,
-                                                                        small_method_threshold,
-                                                                        tiny_method_threshold,
-                                                                        num_dex_methods_threshold,
-                                                                        generate_gdb_information,
-                                                                        include_patch_information,
-                                                                        top_k_profile_threshold,
-                                                                        include_debug_symbols,
-                                                                        implicit_null_checks,
-                                                                        implicit_so_checks,
-                                                                        implicit_suspend_checks
+  std::unique_ptr<CompilerOptions> compiler_options(
+      new CompilerOptions(compiler_filter,
+                          huge_method_threshold,
+                          large_method_threshold,
+                          small_method_threshold,
+                          tiny_method_threshold,
+                          num_dex_methods_threshold,
+                          generate_gdb_information,
+                          include_patch_information,
+                          top_k_profile_threshold,
+                          include_debug_symbols,
+                          implicit_null_checks,
+                          implicit_so_checks,
+                          implicit_suspend_checks,
+                          compile_pic,
 #ifdef ART_SEA_IR_MODE
-                                                                        , compiler_options.sea_ir_ =
-                                                                              true;
+                          true,
 #endif
-  ));  // NOLINT(whitespace/parens)
+                          verbose_methods.empty() ? nullptr : &verbose_methods));
 
   // Done with usage checks, enable watchdog if requested
   WatchDog watch_dog(watch_dog_enabled);
@@ -1263,6 +1273,7 @@
 
   RuntimeOptions runtime_options;
   std::vector<const DexFile*> boot_class_path;
+  art::MemMap::Init();  // For ZipEntry::ExtractToMemMap.
   if (boot_image_option.empty()) {
     size_t failure_count = OpenDexFiles(dex_filenames, dex_locations, boot_class_path);
     if (failure_count > 0) {
@@ -1283,8 +1294,7 @@
   QuickCompilerCallbacks callbacks(verification_results.get(), &method_inliner_map);
   runtime_options.push_back(std::make_pair("compilercallbacks", &callbacks));
   runtime_options.push_back(
-      std::make_pair("imageinstructionset",
-                     reinterpret_cast<const void*>(GetInstructionSetString(instruction_set))));
+      std::make_pair("imageinstructionset", GetInstructionSetString(instruction_set)));
 
   Dex2Oat* p_dex2oat;
   if (!Dex2Oat::Create(&p_dex2oat,
@@ -1292,7 +1302,7 @@
                        *compiler_options,
                        compiler_kind,
                        instruction_set,
-                       instruction_set_features,
+                       instruction_set_features.get(),
                        verification_results.get(),
                        &method_inliner_map,
                        thread_count)) {
diff --git a/disassembler/Android.mk b/disassembler/Android.mk
index d67c169..eb3b024 100644
--- a/disassembler/Android.mk
+++ b/disassembler/Android.mk
@@ -63,6 +63,7 @@
   	$(call set-target-local-cflags-vars,$(2))
   else # host
     LOCAL_CLANG := $(ART_HOST_CLANG)
+    LOCAL_LDLIBS := $(ART_HOST_LDLIBS)
     LOCAL_CFLAGS += $(ART_HOST_CFLAGS)
     ifeq ($$(art_ndebug_or_debug),debug)
       LOCAL_CFLAGS += $(ART_HOST_DEBUG_CFLAGS)
diff --git a/disassembler/disassembler.cc b/disassembler/disassembler.cc
index c97bf64..bf68204 100644
--- a/disassembler/disassembler.cc
+++ b/disassembler/disassembler.cc
@@ -16,7 +16,7 @@
 
 #include "disassembler.h"
 
-#include <iostream>
+#include <ostream>
 
 #include "base/logging.h"
 #include "base/stringprintf.h"
diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc
index ac883fe..ee652b3 100644
--- a/disassembler/disassembler_arm.cc
+++ b/disassembler/disassembler_arm.cc
@@ -18,7 +18,8 @@
 
 #include <inttypes.h>
 
-#include <iostream>
+#include <ostream>
+#include <sstream>
 
 #include "base/logging.h"
 #include "base/stringprintf.h"
diff --git a/disassembler/disassembler_arm64.cc b/disassembler/disassembler_arm64.cc
index 5d0c218..229ac97 100644
--- a/disassembler/disassembler_arm64.cc
+++ b/disassembler/disassembler_arm64.cc
@@ -18,7 +18,7 @@
 
 #include <inttypes.h>
 
-#include <iostream>
+#include <ostream>
 
 #include "base/logging.h"
 #include "base/stringprintf.h"
@@ -27,15 +27,11 @@
 namespace art {
 namespace arm64 {
 
-static uint32_t ReadU32(const uint8_t* ptr) {
-  return *((const uint32_t*)ptr);
-}
-
 size_t DisassemblerArm64::Dump(std::ostream& os, const uint8_t* begin) {
-  uint32_t instruction = ReadU32(begin);
-  decoder.Decode(reinterpret_cast<vixl::Instruction*>(&instruction));
+  const vixl::Instruction* instr = reinterpret_cast<const vixl::Instruction*>(begin);
+  decoder.Decode(instr);
   os << FormatInstructionPointer(begin)
-     << StringPrintf(": %08x\t%s\n", instruction, disasm.GetOutput());
+     << StringPrintf(": %08x\t%s\n", instr->InstructionBits(), disasm.GetOutput());
   return vixl::kInstructionSize;
 }
 
diff --git a/disassembler/disassembler_mips.cc b/disassembler/disassembler_mips.cc
index bd5fac7..97c06f1 100644
--- a/disassembler/disassembler_mips.cc
+++ b/disassembler/disassembler_mips.cc
@@ -16,7 +16,8 @@
 
 #include "disassembler_mips.h"
 
-#include <iostream>
+#include <ostream>
+#include <sstream>
 
 #include "base/logging.h"
 #include "base/stringprintf.h"
diff --git a/disassembler/disassembler_x86.cc b/disassembler/disassembler_x86.cc
index 63a74c7..e12559f 100644
--- a/disassembler/disassembler_x86.cc
+++ b/disassembler/disassembler_x86.cc
@@ -16,12 +16,14 @@
 
 #include "disassembler_x86.h"
 
-#include <iostream>
+#include <inttypes.h>
+
+#include <ostream>
+#include <sstream>
 
 #include "base/logging.h"
 #include "base/stringprintf.h"
 #include "thread.h"
-#include <inttypes.h>
 
 namespace art {
 namespace x86 {
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 1f2c0aa..14accac 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -396,8 +396,13 @@
     os << "INSTRUCTION SET:\n";
     os << oat_header.GetInstructionSet() << "\n\n";
 
-    os << "INSTRUCTION SET FEATURES:\n";
-    os << oat_header.GetInstructionSetFeatures().GetFeatureString() << "\n\n";
+    {
+      std::unique_ptr<const InstructionSetFeatures> features(
+          InstructionSetFeatures::FromBitmap(oat_header.GetInstructionSet(),
+                                             oat_header.GetInstructionSetFeaturesBitmap()));
+      os << "INSTRUCTION SET FEATURES:\n";
+      os << features->GetFeatureString() << "\n\n";
+    }
 
     os << "DEX FILE COUNT:\n";
     os << oat_header.GetDexFileCount() << "\n\n";
@@ -1493,7 +1498,7 @@
   const void* GetQuickOatCodeBegin(mirror::ArtMethod* m)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     const void* quick_code = m->GetEntryPointFromQuickCompiledCode();
-    if (quick_code == Runtime::Current()->GetClassLinker()->GetQuickResolutionTrampoline()) {
+    if (Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(quick_code)) {
       quick_code = oat_dumper_->GetQuickOatCode(m);
     }
     if (oat_dumper_->GetInstructionSet() == kThumb2) {
@@ -2225,6 +2230,8 @@
     runtime.reset(StartRuntime(args.boot_image_location_,
                                args.image_location_,
                                args.instruction_set_));
+  } else {
+    MemMap::Init();
   }
 
   if (args.oat_filename_ != nullptr) {
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 2d165b0..8e5af53 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -24,9 +24,11 @@
 #include <string>
 #include <vector>
 
+#include "base/dumpable.h"
 #include "base/scoped_flock.h"
 #include "base/stringpiece.h"
 #include "base/stringprintf.h"
+#include "base/unix_file/fd_file.h"
 #include "elf_utils.h"
 #include "elf_file.h"
 #include "elf_file_impl.h"
@@ -513,7 +515,7 @@
 }
 
 bool PatchOat::PatchElf() {
-  if (oat_file_->is_elf64_)
+  if (oat_file_->Is64Bit())
     return PatchElf<ElfFileImpl64>(oat_file_->GetImpl64());
   else
     return PatchElf<ElfFileImpl32>(oat_file_->GetImpl32());
@@ -531,13 +533,12 @@
   }
 
   bool need_fixup = false;
-  for (unsigned int i = 0; i < oat_file->GetProgramHeaderNum(); i++) {
+  for (unsigned int i = 0; i < oat_file->GetProgramHeaderNum(); ++i) {
     auto hdr = oat_file->GetProgramHeader(i);
-    if (hdr->p_vaddr != 0 && hdr->p_vaddr != hdr->p_offset) {
+    if ((hdr->p_vaddr != 0 && hdr->p_vaddr != hdr->p_offset) ||
+        (hdr->p_paddr != 0 && hdr->p_paddr != hdr->p_offset)) {
       need_fixup = true;
-    }
-    if (hdr->p_paddr != 0 && hdr->p_paddr != hdr->p_offset) {
-      need_fixup = true;
+      break;
     }
   }
   if (!need_fixup) {
@@ -644,8 +645,7 @@
   va_end(ap);
 }
 
-static void Usage(const char *fmt, ...) NO_RETURN;
-static void Usage(const char *fmt, ...) {
+[[noreturn]] static void Usage(const char *fmt, ...) {
   va_list ap;
   va_start(ap, fmt);
   UsageErrorV(fmt, ap);
@@ -759,6 +759,7 @@
 
 static int patchoat(int argc, char **argv) {
   InitLogging(argv);
+  MemMap::Init();
   const bool debug = kIsDebugBuild;
   orig_argc = argc;
   orig_argv = argv;
@@ -801,7 +802,7 @@
   bool dump_timings = kIsDebugBuild;
   bool lock_output = true;
 
-  for (int i = 0; i < argc; i++) {
+  for (int i = 0; i < argc; ++i) {
     const StringPiece option(argv[i]);
     const bool log_options = false;
     if (log_options) {
diff --git a/patchoat/patchoat.h b/patchoat/patchoat.h
index 7dd95f5..fd36ad5 100644
--- a/patchoat/patchoat.h
+++ b/patchoat/patchoat.h
@@ -52,7 +52,8 @@
  private:
   // Takes ownership only of the ElfFile. All other pointers are only borrowed.
   PatchOat(ElfFile* oat_file, off_t delta, TimingLogger* timings)
-      : oat_file_(oat_file), delta_(delta), timings_(timings) {}
+      : oat_file_(oat_file), image_(nullptr), bitmap_(nullptr), heap_(nullptr), delta_(delta),
+        timings_(timings) {}
   PatchOat(MemMap* image, gc::accounting::ContinuousSpaceBitmap* bitmap,
            MemMap* heap, off_t delta, TimingLogger* timings)
       : image_(image), bitmap_(bitmap), heap_(heap),
@@ -106,21 +107,22 @@
     void operator() (mirror::Class* cls, mirror::Reference* ref) const
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_);
   private:
-    PatchOat* patcher_;
-    mirror::Object* copy_;
+    PatchOat* const patcher_;
+    mirror::Object* const copy_;
   };
 
   // The elf file we are patching.
   std::unique_ptr<ElfFile> oat_file_;
   // A mmap of the image we are patching. This is modified.
-  const MemMap* image_;
+  const MemMap* const image_;
+  // The bitmap over the image within the heap we are patching. This is not modified.
+  gc::accounting::ContinuousSpaceBitmap* const bitmap_;
   // The heap we are patching. This is not modified.
-  gc::accounting::ContinuousSpaceBitmap* bitmap_;
-  // The heap we are patching. This is not modified.
-  const MemMap* heap_;
+  const MemMap* const heap_;
   // The amount we are changing the offset by.
-  off_t delta_;
-  TimingLogger* timings_;
+  const off_t delta_;
+  // Timing splits.
+  TimingLogger* const timings_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(PatchOat);
 };
diff --git a/runtime/Android.mk b/runtime/Android.mk
index e954476..0ef0fef 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -209,7 +209,6 @@
 
 LIBART_TARGET_SRC_FILES := \
   $(LIBART_COMMON_SRC_FILES) \
-  base/logging_android.cc \
   jdwp/jdwp_adb.cc \
   monitor_android.cc \
   runtime_android.cc \
@@ -218,11 +217,11 @@
 LIBART_TARGET_SRC_FILES_arm := \
   arch/arm/context_arm.cc.arm \
   arch/arm/entrypoints_init_arm.cc \
+  arch/arm/instruction_set_features_arm.S \
   arch/arm/jni_entrypoints_arm.S \
   arch/arm/memcmp16_arm.S \
   arch/arm/portable_entrypoints_arm.S \
   arch/arm/quick_entrypoints_arm.S \
-  arch/arm/arm_sdiv.S \
   arch/arm/thread_arm.cc \
   arch/arm/fault_handler_arm.cc
 
@@ -282,7 +281,6 @@
 
 LIBART_HOST_SRC_FILES := \
   $(LIBART_COMMON_SRC_FILES) \
-  base/logging_linux.cc \
   monitor_linux.cc \
   runtime_linux.cc \
   thread_linux.cc
@@ -317,7 +315,7 @@
   thread_state.h \
   verifier/method_verifier.h
 
-LIBART_CFLAGS :=
+LIBART_CFLAGS := -DBUILDING_LIBART=1
 ifeq ($(ART_USE_PORTABLE_COMPILER),true)
   LIBART_CFLAGS += -DART_USE_PORTABLE_COMPILER=1
 endif
@@ -328,6 +326,29 @@
   LIBART_CFLAGS += -DUSE_JEMALLOC
 endif
 
+# Default dex2oat instruction set features.
+LIBART_HOST_DEFAULT_INSTRUCTION_SET_FEATURES := default
+LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES := default
+2ND_LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES := default
+ifeq ($(DEX2OAT_TARGET_ARCH),arm)
+  ifneq (,$(filter $(DEX2OAT_TARGET_CPU_VARIANT),cortex-a15 krait denver))
+    LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES := lpae,div
+  else
+    ifneq (,$(filter $(DEX2OAT_TARGET_CPU_VARIANT),cortex-a7))
+      LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES := div
+    endif
+  endif
+endif
+ifeq ($(2ND_DEX2OAT_TARGET_ARCH),arm)
+  ifneq (,$(filter $(DEX2OAT_TARGET_CPU_VARIANT),cortex-a15 krait denver))
+    2ND_LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES := lpae,div
+  else
+    ifneq (,$(filter $(DEX2OAT_TARGET_CPU_VARIANT),cortex-a7))
+      2ND_LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES := div
+    endif
+  endif
+endif
+
 # $(1): target or host
 # $(2): ndebug or debug
 define build-libart
@@ -346,6 +367,13 @@
   art_ndebug_or_debug := $(2)
 
   include $$(CLEAR_VARS)
+  # Clang assembler has problem with macros in asm_support_x86.S, http://b/17443165,
+  # on linux. Yet sdk on mac needs integrated assembler.
+  ifeq ($$(HOST_OS),darwin)
+    LOCAL_CLANG_ASFLAGS += -integrated-as
+  else
+    LOCAL_CLANG_ASFLAGS += -no-integrated-as
+  endif
   LOCAL_CPP_EXTENSION := $$(ART_CPP_EXTENSION)
   ifeq ($$(art_ndebug_or_debug),ndebug)
     LOCAL_MODULE := libart
@@ -393,6 +421,9 @@
   ifeq ($$(art_target_or_host),target)
     $$(eval $$(call set-target-local-clang-vars))
     $$(eval $$(call set-target-local-cflags-vars,$(2)))
+    LOCAL_CFLAGS_$(DEX2OAT_TARGET_ARCH) += -DART_DEFAULT_INSTRUCTION_SET_FEATURES="$(LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES)"
+    LOCAL_CFLAGS_$(2ND_DEX2OAT_TARGET_ARCH) += -DART_DEFAULT_INSTRUCTION_SET_FEATURES="$(2ND_LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES)"
+
     # TODO: Loop with ifeq, ART_TARGET_CLANG
     ifneq ($$(ART_TARGET_CLANG_$$(TARGET_ARCH)),true)
       LOCAL_SRC_FILES_$$(TARGET_ARCH) += $$(LIBART_GCC_ONLY_SRC_FILES)
@@ -401,18 +432,25 @@
       LOCAL_SRC_FILES_$$(TARGET_2ND_ARCH) += $$(LIBART_GCC_ONLY_SRC_FILES)
     endif
   else # host
-    LOCAL_CLANG := $$(ART_HOST_CLANG)
-    ifeq ($$(ART_HOST_CLANG),false)
+    ifneq ($$(ART_HOST_CLANG),true)
+      # Add files only built with GCC on the host.
       LOCAL_SRC_FILES += $$(LIBART_GCC_ONLY_SRC_FILES)
     endif
+    LOCAL_CLANG := $$(ART_HOST_CLANG)
+    LOCAL_LDLIBS := $$(ART_HOST_LDLIBS)
+    LOCAL_LDLIBS += -ldl -lpthread
+    ifeq ($$(HOST_OS),linux)
+      LOCAL_LDLIBS += -lrt
+    endif
     LOCAL_CFLAGS += $$(ART_HOST_CFLAGS)
+    LOCAL_CFLAGS += -DART_DEFAULT_INSTRUCTION_SET_FEATURES="$(LIBART_HOST_DEFAULT_INSTRUCTION_SET_FEATURES)"
+
     ifeq ($$(art_ndebug_or_debug),debug)
       LOCAL_CFLAGS += $$(ART_HOST_DEBUG_CFLAGS)
-      LOCAL_LDLIBS += $$(ART_HOST_DEBUG_LDLIBS)
-      LOCAL_STATIC_LIBRARIES := libgtest_host
     else
       LOCAL_CFLAGS += $$(ART_HOST_NON_DEBUG_CFLAGS)
     endif
+    LOCAL_MULTILIB := both
   endif
 
   LOCAL_C_INCLUDES += $$(ART_C_INCLUDES)
@@ -427,11 +465,6 @@
   else # host
     LOCAL_STATIC_LIBRARIES += libcutils libziparchive-host libz libutils
     LOCAL_SHARED_LIBRARIES += libsigchain
-    LOCAL_LDLIBS += -ldl -lpthread
-    ifeq ($$(HOST_OS),linux)
-      LOCAL_LDLIBS += -lrt
-    endif
-    LOCAL_MULTILIB := both
   endif
   ifeq ($$(ART_USE_PORTABLE_COMPILER),true)
     include $$(LLVM_GEN_INTRINSICS_MK)
@@ -442,7 +475,7 @@
     endif
   endif
   LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
-#  LOCAL_ADDITIONAL_DEPENDENCIES += $$(LOCAL_PATH)/Android.mk
+  LOCAL_ADDITIONAL_DEPENDENCIES += $$(LOCAL_PATH)/Android.mk
 
   ifeq ($$(art_target_or_host),target)
     LOCAL_MODULE_TARGET_ARCH := $$(ART_TARGET_SUPPORTED_ARCH)
@@ -488,6 +521,9 @@
 LOCAL_PATH :=
 LIBART_COMMON_SRC_FILES :=
 LIBART_GCC_ONLY_SRC_FILES :=
+LIBART_HOST_DEFAULT_INSTRUCTION_SET_FEATURES :=
+LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES :=
+2ND_LIBART_TARGET_DEFAULT_INSTRUCTION_SET_FEATURES :=
 LIBART_TARGET_LDFLAGS :=
 LIBART_HOST_LDFLAGS :=
 LIBART_TARGET_SRC_FILES :=
diff --git a/runtime/arch/arch_test.cc b/runtime/arch/arch_test.cc
index 5220dc3..42bf8fb 100644
--- a/runtime/arch/arch_test.cc
+++ b/runtime/arch/arch_test.cc
@@ -43,398 +43,98 @@
   }
 };
 
+// Common tests are declared next to the constants.
+#define ADD_TEST_EQ(x, y) EXPECT_EQ(x, y);
+#include "asm_support.h"
 
-TEST_F(ArchTest, ARM) {
+TEST_F(ArchTest, CheckCommonOffsetsAndSizes) {
+  CheckAsmSupportOffsetsAndSizes();
+}
+
+// Grab architecture specific constants.
+namespace arm {
 #include "arch/arm/asm_support_arm.h"
-#undef ART_RUNTIME_ARCH_ARM_ASM_SUPPORT_ARM_H_
-
-
-#ifdef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
-  CheckFrameSize(InstructionSet::kArm, Runtime::kSaveAll, FRAME_SIZE_SAVE_ALL_CALLEE_SAVE);
-#else
-  LOG(WARNING) << "No frame size for SaveAll";
-#endif
-#ifdef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
-  CheckFrameSize(InstructionSet::kArm, Runtime::kRefsOnly, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE);
-#else
-  LOG(WARNING) << "No frame size for RefsOnly";
-#endif
-#ifdef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
-  CheckFrameSize(InstructionSet::kArm, Runtime::kRefsAndArgs, FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE);
-#else
-  LOG(WARNING) << "No frame size for RefsAndArgs";
-#endif
-
-
-#ifdef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
-#undef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
-#endif
-#ifdef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
-#undef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
-#endif
-#ifdef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
-#undef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
-#endif
-#ifdef THREAD_SELF_OFFSET
-#undef THREAD_SELF_OFFSET
-#endif
-#ifdef THREAD_CARD_TABLE_OFFSET
-#undef THREAD_CARD_TABLE_OFFSET
-#endif
-#ifdef THREAD_EXCEPTION_OFFSET
-#undef THREAD_EXCEPTION_OFFSET
-#endif
-#ifdef THREAD_ID_OFFSET
-#undef THREAD_ID_OFFSET
-#endif
-#ifdef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+static constexpr size_t kFrameSizeSaveAllCalleeSave = FRAME_SIZE_SAVE_ALL_CALLEE_SAVE;
 #undef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
-#endif
-#ifdef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+static constexpr size_t kFrameSizeRefsOnlyCalleeSave = FRAME_SIZE_REFS_ONLY_CALLEE_SAVE;
 #undef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
-#endif
-#ifdef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+static constexpr size_t kFrameSizeRefsAndArgsCalleeSave = FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE;
 #undef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
-#endif
-#ifdef HEAP_REFERENCE_SIZE
-#undef HEAP_REFERENCE_SIZE
-#endif
+}
+
+namespace arm64 {
+#include "arch/arm64/asm_support_arm64.h"
+static constexpr size_t kFrameSizeSaveAllCalleeSave = FRAME_SIZE_SAVE_ALL_CALLEE_SAVE;
+#undef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+static constexpr size_t kFrameSizeRefsOnlyCalleeSave = FRAME_SIZE_REFS_ONLY_CALLEE_SAVE;
+#undef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+static constexpr size_t kFrameSizeRefsAndArgsCalleeSave = FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE;
+#undef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+}
+
+namespace mips {
+#include "arch/mips/asm_support_mips.h"
+static constexpr size_t kFrameSizeSaveAllCalleeSave = FRAME_SIZE_SAVE_ALL_CALLEE_SAVE;
+#undef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+static constexpr size_t kFrameSizeRefsOnlyCalleeSave = FRAME_SIZE_REFS_ONLY_CALLEE_SAVE;
+#undef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+static constexpr size_t kFrameSizeRefsAndArgsCalleeSave = FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE;
+#undef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+}
+
+namespace x86 {
+#include "arch/x86/asm_support_x86.h"
+static constexpr size_t kFrameSizeSaveAllCalleeSave = FRAME_SIZE_SAVE_ALL_CALLEE_SAVE;
+#undef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+static constexpr size_t kFrameSizeRefsOnlyCalleeSave = FRAME_SIZE_REFS_ONLY_CALLEE_SAVE;
+#undef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+static constexpr size_t kFrameSizeRefsAndArgsCalleeSave = FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE;
+#undef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+}
+
+namespace x86_64 {
+#include "arch/x86_64/asm_support_x86_64.h"
+static constexpr size_t kFrameSizeSaveAllCalleeSave = FRAME_SIZE_SAVE_ALL_CALLEE_SAVE;
+#undef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+static constexpr size_t kFrameSizeRefsOnlyCalleeSave = FRAME_SIZE_REFS_ONLY_CALLEE_SAVE;
+#undef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+static constexpr size_t kFrameSizeRefsAndArgsCalleeSave = FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE;
+#undef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+}
+
+// Check architecture specific constants are sound.
+TEST_F(ArchTest, ARM) {
+  CheckFrameSize(InstructionSet::kArm, Runtime::kSaveAll, arm::kFrameSizeSaveAllCalleeSave);
+  CheckFrameSize(InstructionSet::kArm, Runtime::kRefsOnly, arm::kFrameSizeRefsOnlyCalleeSave);
+  CheckFrameSize(InstructionSet::kArm, Runtime::kRefsAndArgs, arm::kFrameSizeRefsAndArgsCalleeSave);
 }
 
 
 TEST_F(ArchTest, ARM64) {
-#include "arch/arm64/asm_support_arm64.h"
-#undef ART_RUNTIME_ARCH_ARM64_ASM_SUPPORT_ARM64_H_
-
-
-#ifdef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
-  CheckFrameSize(InstructionSet::kArm64, Runtime::kSaveAll, FRAME_SIZE_SAVE_ALL_CALLEE_SAVE);
-#else
-  LOG(WARNING) << "No frame size for SaveAll";
-#endif
-#ifdef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
-  CheckFrameSize(InstructionSet::kArm64, Runtime::kRefsOnly, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE);
-#else
-  LOG(WARNING) << "No frame size for RefsOnly";
-#endif
-#ifdef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
-  CheckFrameSize(InstructionSet::kArm64, Runtime::kRefsAndArgs, FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE);
-#else
-  LOG(WARNING) << "No frame size for RefsAndArgs";
-#endif
-
-
-#ifdef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
-#undef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
-#endif
-#ifdef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
-#undef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
-#endif
-#ifdef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
-#undef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
-#endif
-#ifdef THREAD_SELF_OFFSET
-#undef THREAD_SELF_OFFSET
-#endif
-#ifdef THREAD_CARD_TABLE_OFFSET
-#undef THREAD_CARD_TABLE_OFFSET
-#endif
-#ifdef THREAD_EXCEPTION_OFFSET
-#undef THREAD_EXCEPTION_OFFSET
-#endif
-#ifdef THREAD_ID_OFFSET
-#undef THREAD_ID_OFFSET
-#endif
-#ifdef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
-#undef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
-#endif
-#ifdef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
-#undef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
-#endif
-#ifdef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
-#undef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
-#endif
-#ifdef HEAP_REFERENCE_SIZE
-#undef HEAP_REFERENCE_SIZE
-#endif
+  CheckFrameSize(InstructionSet::kArm64, Runtime::kSaveAll, arm64::kFrameSizeSaveAllCalleeSave);
+  CheckFrameSize(InstructionSet::kArm64, Runtime::kRefsOnly, arm64::kFrameSizeRefsOnlyCalleeSave);
+  CheckFrameSize(InstructionSet::kArm64, Runtime::kRefsAndArgs,
+                 arm64::kFrameSizeRefsAndArgsCalleeSave);
 }
 
-
 TEST_F(ArchTest, MIPS) {
-#include "arch/mips/asm_support_mips.h"
-#undef ART_RUNTIME_ARCH_MIPS_ASM_SUPPORT_MIPS_H_
-
-
-#ifdef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
-  CheckFrameSize(InstructionSet::kMips, Runtime::kSaveAll, FRAME_SIZE_SAVE_ALL_CALLEE_SAVE);
-#else
-  LOG(WARNING) << "No frame size for SaveAll";
-#endif
-#ifdef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
-  CheckFrameSize(InstructionSet::kMips, Runtime::kRefsOnly, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE);
-#else
-  LOG(WARNING) << "No frame size for RefsOnly";
-#endif
-#ifdef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
-  CheckFrameSize(InstructionSet::kMips, Runtime::kRefsAndArgs, FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE);
-#else
-  LOG(WARNING) << "No frame size for RefsAndArgs";
-#endif
-
-
-#ifdef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
-#undef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
-#endif
-#ifdef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
-#undef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
-#endif
-#ifdef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
-#undef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
-#endif
-#ifdef THREAD_SELF_OFFSET
-#undef THREAD_SELF_OFFSET
-#endif
-#ifdef THREAD_CARD_TABLE_OFFSET
-#undef THREAD_CARD_TABLE_OFFSET
-#endif
-#ifdef THREAD_EXCEPTION_OFFSET
-#undef THREAD_EXCEPTION_OFFSET
-#endif
-#ifdef THREAD_ID_OFFSET
-#undef THREAD_ID_OFFSET
-#endif
-#ifdef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
-#undef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
-#endif
-#ifdef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
-#undef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
-#endif
-#ifdef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
-#undef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
-#endif
-#ifdef HEAP_REFERENCE_SIZE
-#undef HEAP_REFERENCE_SIZE
-#endif
+  CheckFrameSize(InstructionSet::kMips, Runtime::kSaveAll, mips::kFrameSizeSaveAllCalleeSave);
+  CheckFrameSize(InstructionSet::kMips, Runtime::kRefsOnly, mips::kFrameSizeRefsOnlyCalleeSave);
+  CheckFrameSize(InstructionSet::kMips, Runtime::kRefsAndArgs,
+                 mips::kFrameSizeRefsAndArgsCalleeSave);
 }
 
-
 TEST_F(ArchTest, X86) {
-#include "arch/x86/asm_support_x86.h"
-#undef ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_H_
-
-
-#ifdef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
-  CheckFrameSize(InstructionSet::kX86, Runtime::kSaveAll, FRAME_SIZE_SAVE_ALL_CALLEE_SAVE);
-#else
-  LOG(WARNING) << "No frame size for SaveAll";
-#endif
-#ifdef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
-  CheckFrameSize(InstructionSet::kX86, Runtime::kRefsOnly, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE);
-#else
-  LOG(WARNING) << "No frame size for RefsOnly";
-#endif
-#ifdef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
-  CheckFrameSize(InstructionSet::kX86, Runtime::kRefsAndArgs, FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE);
-#else
-  LOG(WARNING) << "No frame size for RefsAndArgs";
-#endif
-
-
-#ifdef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
-#undef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
-#endif
-#ifdef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
-#undef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
-#endif
-#ifdef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
-#undef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
-#endif
-#ifdef THREAD_SELF_OFFSET
-#undef THREAD_SELF_OFFSET
-#endif
-#ifdef THREAD_CARD_TABLE_OFFSET
-#undef THREAD_CARD_TABLE_OFFSET
-#endif
-#ifdef THREAD_EXCEPTION_OFFSET
-#undef THREAD_EXCEPTION_OFFSET
-#endif
-#ifdef THREAD_ID_OFFSET
-#undef THREAD_ID_OFFSET
-#endif
-#ifdef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
-#undef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
-#endif
-#ifdef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
-#undef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
-#endif
-#ifdef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
-#undef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
-#endif
-#ifdef HEAP_REFERENCE_SIZE
-#undef HEAP_REFERENCE_SIZE
-#endif
+  CheckFrameSize(InstructionSet::kX86, Runtime::kSaveAll, x86::kFrameSizeSaveAllCalleeSave);
+  CheckFrameSize(InstructionSet::kX86, Runtime::kRefsOnly, x86::kFrameSizeRefsOnlyCalleeSave);
+  CheckFrameSize(InstructionSet::kX86, Runtime::kRefsAndArgs, x86::kFrameSizeRefsAndArgsCalleeSave);
 }
 
-
 TEST_F(ArchTest, X86_64) {
-#include "arch/x86_64/asm_support_x86_64.h"
-#undef ART_RUNTIME_ARCH_X86_64_ASM_SUPPORT_X86_64_H_
-
-
-#ifdef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
-  CheckFrameSize(InstructionSet::kX86_64, Runtime::kSaveAll, FRAME_SIZE_SAVE_ALL_CALLEE_SAVE);
-#else
-  LOG(WARNING) << "No frame size for SaveAll";
-#endif
-#ifdef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
-  CheckFrameSize(InstructionSet::kX86_64, Runtime::kRefsOnly, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE);
-#else
-  LOG(WARNING) << "No frame size for RefsOnly";
-#endif
-#ifdef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
-  CheckFrameSize(InstructionSet::kX86_64, Runtime::kRefsAndArgs, FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE);
-#else
-  LOG(WARNING) << "No frame size for RefsAndArgs";
-#endif
-
-
-#ifdef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
-#undef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
-#endif
-#ifdef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
-#undef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
-#endif
-#ifdef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
-#undef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
-#endif
-#ifdef THREAD_SELF_OFFSET
-#undef THREAD_SELF_OFFSET
-#endif
-#ifdef THREAD_CARD_TABLE_OFFSET
-#undef THREAD_CARD_TABLE_OFFSET
-#endif
-#ifdef THREAD_EXCEPTION_OFFSET
-#undef THREAD_EXCEPTION_OFFSET
-#endif
-#ifdef THREAD_ID_OFFSET
-#undef THREAD_ID_OFFSET
-#endif
-#ifdef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
-#undef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
-#endif
-#ifdef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
-#undef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
-#endif
-#ifdef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
-#undef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
-#endif
-#ifdef HEAP_REFERENCE_SIZE
-#undef HEAP_REFERENCE_SIZE
-#endif
-}
-
-
-// The following tests are all for the running architecture. So we get away
-// with just including it and not undefining it every time.
-
-#if defined(__arm__)
-#include "arch/arm/asm_support_arm.h"
-#elif defined(__aarch64__)
-#include "arch/arm64/asm_support_arm64.h"
-#elif defined(__mips__)
-#include "arch/mips/asm_support_mips.h"
-#elif defined(__i386__)
-#include "arch/x86/asm_support_x86.h"
-#elif defined(__x86_64__)
-#include "arch/x86_64/asm_support_x86_64.h"
-#else
-  // This happens for the host test.
-#ifdef __LP64__
-#include "arch/x86_64/asm_support_x86_64.h"
-#else
-#include "arch/x86/asm_support_x86.h"
-#endif
-#endif
-
-
-TEST_F(ArchTest, ThreadOffsets) {
-  // Ugly hack, change when possible.
-#ifdef __LP64__
-#define POINTER_SIZE 8
-#else
-#define POINTER_SIZE 4
-#endif
-
-#if defined(THREAD_SELF_OFFSET)
-  ThreadOffset<POINTER_SIZE> self_offset = Thread::SelfOffset<POINTER_SIZE>();
-  EXPECT_EQ(self_offset.Int32Value(), THREAD_SELF_OFFSET);
-#else
-  LOG(INFO) << "No Thread Self Offset found.";
-#endif
-
-#if defined(THREAD_CARD_TABLE_OFFSET)
-  ThreadOffset<POINTER_SIZE> card_offset = Thread::CardTableOffset<POINTER_SIZE>();
-  EXPECT_EQ(card_offset.Int32Value(), THREAD_CARD_TABLE_OFFSET);
-#else
-  LOG(INFO) << "No Thread Card Table Offset found.";
-#endif
-
-#if defined(THREAD_EXCEPTION_OFFSET)
-  ThreadOffset<POINTER_SIZE> exc_offset = Thread::ExceptionOffset<POINTER_SIZE>();
-    EXPECT_EQ(exc_offset.Int32Value(), THREAD_EXCEPTION_OFFSET);
-#else
-  LOG(INFO) << "No Thread Exception Offset found.";
-#endif
-
-#if defined(THREAD_ID_OFFSET)
-  ThreadOffset<POINTER_SIZE> id_offset = Thread::ThinLockIdOffset<POINTER_SIZE>();
-  EXPECT_EQ(id_offset.Int32Value(), THREAD_ID_OFFSET);
-#else
-  LOG(INFO) << "No Thread ID Offset found.";
-#endif
-}
-
-
-TEST_F(ArchTest, CalleeSaveMethodOffsets) {
-#if defined(RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET)
-  EXPECT_EQ(Runtime::GetCalleeSaveMethodOffset(Runtime::kSaveAll),
-            static_cast<size_t>(RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET));
-#else
-  LOG(INFO) << "No Runtime Save-all Offset found.";
-#endif
-
-#if defined(RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET)
-  EXPECT_EQ(Runtime::GetCalleeSaveMethodOffset(Runtime::kRefsOnly),
-            static_cast<size_t>(RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET));
-#else
-  LOG(INFO) << "No Runtime Refs-only Offset found.";
-#endif
-
-#if defined(RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET)
-  EXPECT_EQ(Runtime::GetCalleeSaveMethodOffset(Runtime::kRefsAndArgs),
-            static_cast<size_t>(RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET));
-#else
-  LOG(INFO) << "No Runtime Refs-and-Args Offset found.";
-#endif
-}
-
-
-TEST_F(ArchTest, HeapReferenceSize) {
-#if defined(HEAP_REFERENCE_SIZE)
-  EXPECT_EQ(sizeof(mirror::HeapReference<mirror::Object>),
-            static_cast<size_t>(HEAP_REFERENCE_SIZE));
-#else
-  LOG(INFO) << "No expected HeapReference Size found.";
-#endif
-}
-
-TEST_F(ArchTest, StackReferenceSize) {
-#if defined(STACK_REFERENCE_SIZE)
-  EXPECT_EQ(sizeof(StackReference<mirror::Object>),
-            static_cast<size_t>(STACK_REFERENCE_SIZE));
-#else
-  LOG(INFO) << "No expected StackReference Size #define found.";
-#endif
+  CheckFrameSize(InstructionSet::kX86_64, Runtime::kSaveAll, x86_64::kFrameSizeSaveAllCalleeSave);
+  CheckFrameSize(InstructionSet::kX86_64, Runtime::kRefsOnly, x86_64::kFrameSizeRefsOnlyCalleeSave);
+  CheckFrameSize(InstructionSet::kX86_64, Runtime::kRefsAndArgs,
+                 x86_64::kFrameSizeRefsAndArgsCalleeSave);
 }
 
 }  // namespace art
diff --git a/runtime/arch/arm/arm_sdiv.S b/runtime/arch/arm/arm_sdiv.S
deleted file mode 100644
index babdbf5..0000000
--- a/runtime/arch/arm/arm_sdiv.S
+++ /dev/null
@@ -1,24 +0,0 @@
-// This function is used to check for the CPU's support for the sdiv
-// instruction at runtime.  It will either return the value 1 or
-// will cause an invalid instruction trap (SIGILL signal).  The
-// caller must arrange for the signal handler to set the r0
-// register to 0 and move the pc forward by 4 bytes (to skip
-// the invalid instruction).
-
-
-#include "asm_support_arm.S"
-
-.section .text
-ENTRY_NO_HIDE CheckForARMSDIVInstruction
-  mov r1,#1
-  // depending on the architecture, the assembler will not allow an
-  // sdiv instruction, so we will have to output the bytes directly.
-
-  // sdiv r0,r1,r1 is two words: 0xfb91 0xf1f0.  We need little endian.
-  .byte 0x91,0xfb,0xf1,0xf0
-
-  // if the divide worked, r0 will have the value #1 (result of sdiv).
-  // It will have 0 otherwise (set by the signal handler)
-  // the value is just returned from this function.
-  bx lr
-  END CheckForARMSDIVInstruction
diff --git a/runtime/arch/arm/asm_support_arm.S b/runtime/arch/arm/asm_support_arm.S
index a3e3b21..2af636e 100644
--- a/runtime/arch/arm/asm_support_arm.S
+++ b/runtime/arch/arm/asm_support_arm.S
@@ -30,63 +30,92 @@
 .arch armv7-a
 .thumb
 
+// Macro to generate the value of Runtime::Current into rDest clobbering rTemp. As it uses labels
+// then the labels need to be unique. We bind these to the function name in the ENTRY macros.
+.macro RUNTIME_CURRENT name, num, rDest, rTemp
+    .if .Lruntime_current\num\()_used
+         .error
+    .endif
+    .set .Lruntime_current\num\()_used, 1
+    ldr \rDest, .Lgot_\name\()_\num               @ Load offset of the GOT.
+    ldr \rTemp, .Lruntime_instance_\name\()_\num  @ Load GOT offset of Runtime::instance_.
+.Lload_got_\name\()_\num\():
+    add \rDest, pc                                @ Fixup GOT address.
+    ldr \rDest, [\rDest, \rTemp]                  @ Load address of Runtime::instance_.
+    ldr \rDest, [\rDest]                          @ Load Runtime::instance_.
+.endm
+
+// Common ENTRY declaration code for ARM and thumb, an ENTRY should always be paired with an END.
+// Declares the RUNTIME_CURRENT[123] macros that can be used within an ENTRY and will have literals
+// generated at END.
+.macro DEF_ENTRY thumb_or_arm, name
+    \thumb_or_arm
+    .type \name, #function
+    .hidden \name  // Hide this as a global symbol, so we do not incur plt calls.
+    .global \name
+    // Cache alignment for function entry.
+    .balign 16
+\name:
+    .cfi_startproc
+    .fnstart
+    // Track whether RUNTIME_CURRENT was used.
+    .set .Lruntime_current1_used, 0
+    .set .Lruntime_current2_used, 0
+    .set .Lruntime_current3_used, 0
+    // The RUNTIME_CURRENT macros that are bound to the \name argument of DEF_ENTRY to ensure
+    // that label names are unique.
+    .macro RUNTIME_CURRENT1 rDest, rTemp
+        RUNTIME_CURRENT \name, 1, \rDest, \rTemp
+    .endm
+    .macro RUNTIME_CURRENT2 rDest, rTemp
+        RUNTIME_CURRENT \name, 2, \rDest, \rTemp
+    .endm
+    .macro RUNTIME_CURRENT3 rDest, rTemp
+        RUNTIME_CURRENT \name, 3, \rDest, \rTemp
+    .endm
+.endm
+
+// A thumb2 style ENTRY.
 .macro ENTRY name
-    .thumb_func
-    .type \name, #function
-    .hidden \name  // Hide this as a global symbol, so we do not incur plt calls.
-    .global \name
-    /* Cache alignment for function entry */
-    .balign 16
-\name:
-    .cfi_startproc
-    .fnstart
+    DEF_ENTRY .thumb_func, \name
 .endm
 
-.macro ENTRY_NO_HIDE name
-    .thumb_func
-    .type \name, #function
-    .global \name
-    /* Cache alignment for function entry */
-    .balign 16
-\name:
-    .cfi_startproc
-    .fnstart
-.endm
-
-
+// A ARM style ENTRY.
 .macro ARM_ENTRY name
-    .arm
-    .type \name, #function
-    .hidden \name  // Hide this as a global symbol, so we do not incur plt calls.
-    .global \name
-    /* Cache alignment for function entry */
-    .balign 16
-\name:
-    .cfi_startproc
-     /* Ensure we get a sane starting CFA. */
-    .cfi_def_cfa sp,0
-    .fnstart
+    DEF_ENTRY .arm, \name
 .endm
 
-.macro ARM_ENTRY_NO_HIDE name
-    .arm
-    .type \name, #function
-    .global \name
-    /* Cache alignment for function entry */
-    .balign 16
-\name:
-    .cfi_startproc
-     /* Ensure we get a sane starting CFA. */
-    .cfi_def_cfa sp,0
-    .fnstart
-.endm
-
+// Terminate an ENTRY and generate GOT references.
 .macro END name
+     // Generate offsets of GOT and Runtime::instance_ used in RUNTIME_CURRENT.
+     .if .Lruntime_current1_used
+         .Lgot_\name\()_1:
+             .word   _GLOBAL_OFFSET_TABLE_-(.Lload_got_\name\()_1+4)
+         .Lruntime_instance_\name\()_1:
+             .word   _ZN3art7Runtime9instance_E(GOT)
+     .endif
+     .if .Lruntime_current2_used
+         .Lgot_\name\()_2:
+             .word   _GLOBAL_OFFSET_TABLE_-(.Lload_got_\name\()_2+4)
+         .Lruntime_instance_\name\()_2:
+             .word   _ZN3art7Runtime9instance_E(GOT)
+    .endif
+     .if .Lruntime_current3_used
+         .Lgot_\name\()_3:
+             .word   _GLOBAL_OFFSET_TABLE_-(.Lload_got_\name\()_3+4)
+         .Lruntime_instance_\name\()_3:
+             .word   _ZN3art7Runtime9instance_E(GOT)
+    .endif
+    // Remove the RUNTIME_CURRENTx macros so they get rebound in the next function entry.
+    .purgem RUNTIME_CURRENT1
+    .purgem RUNTIME_CURRENT2
+    .purgem RUNTIME_CURRENT3
     .fnend
     .cfi_endproc
     .size \name, .-\name
 .endm
 
+// Declare an unimplemented ENTRY that will halt a debugger.
 .macro UNIMPLEMENTED name
     ENTRY \name
     bkpt
diff --git a/runtime/arch/arm/asm_support_arm.h b/runtime/arch/arm/asm_support_arm.h
index 330924e..5388cc0 100644
--- a/runtime/arch/arm/asm_support_arm.h
+++ b/runtime/arch/arm/asm_support_arm.h
@@ -19,21 +19,10 @@
 
 #include "asm_support.h"
 
-// Offset of field Thread::tls32_.state_and_flags verified in InitCpu
-#define THREAD_FLAGS_OFFSET 0
-// Offset of field Thread::tls32_.thin_lock_thread_id verified in InitCpu
-#define THREAD_ID_OFFSET 12
-// Offset of field Thread::tlsPtr_.card_table verified in InitCpu
-#define THREAD_CARD_TABLE_OFFSET 120
-// Offset of field Thread::tlsPtr_.exception verified in InitCpu
-#define THREAD_EXCEPTION_OFFSET 124
-
 #define FRAME_SIZE_SAVE_ALL_CALLEE_SAVE 176
 #define FRAME_SIZE_REFS_ONLY_CALLEE_SAVE 32
 #define FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE 48
 
-// Expected size of a heap reference
-#define HEAP_REFERENCE_SIZE 4
 // Flag for enabling R4 optimization in arm runtime
 #define ARM_R4_SUSPEND_FLAG
 
diff --git a/runtime/arch/arm/entrypoints_init_arm.cc b/runtime/arch/arm/entrypoints_init_arm.cc
index 2780d1b..ff0eb4a 100644
--- a/runtime/arch/arm/entrypoints_init_arm.cc
+++ b/runtime/arch/arm/entrypoints_init_arm.cc
@@ -21,17 +21,11 @@
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "entrypoints/entrypoint_utils.h"
 #include "entrypoints/math_entrypoints.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
+#include "interpreter/interpreter.h"
 
 namespace art {
 
-// Interpreter entrypoints.
-extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh,
-                                                  const DexFile::CodeItem* code_item,
-                                                  ShadowFrame* shadow_frame, JValue* result);
-extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh,
-                                                   const DexFile::CodeItem* code_item,
-                                                   ShadowFrame* shadow_frame, JValue* result);
-
 // Portable entrypoints.
 extern "C" void art_portable_resolution_trampoline(mirror::ArtMethod*);
 extern "C" void art_portable_to_interpreter_bridge(mirror::ArtMethod*);
diff --git a/runtime/arch/arm/instruction_set_features_arm.S b/runtime/arch/arm/instruction_set_features_arm.S
new file mode 100644
index 0000000..c26f2cd
--- /dev/null
+++ b/runtime/arch/arm/instruction_set_features_arm.S
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 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 "asm_support_arm.S"
+
+.section .text
+// This function is used to check for the CPU's support for the sdiv
+// instruction at runtime.  It will either return the value 1 or
+// will cause an invalid instruction trap (SIGILL signal).  The
+// caller must arrange for the signal handler to set the r0
+// register to 0 and move the pc forward by 4 bytes (to skip
+// the invalid instruction).
+ENTRY artCheckForARMSDIVInstruction
+  mov r1,#1
+  // depending on the architecture, the assembler will not allow an
+  // sdiv instruction, so we will have to output the bytes directly.
+
+  // sdiv r0,r1,r1 is two words: 0xfb91 0xf1f0.  We need little endian.
+  .byte 0x91,0xfb,0xf1,0xf0
+
+  // if the divide worked, r0 will have the value #1 (result of sdiv).
+  // It will have 0 otherwise (set by the signal handler)
+  // the value is just returned from this function.
+  bx lr
+END artCheckForARMSDIVInstruction
diff --git a/runtime/arch/arm/portable_entrypoints_arm.S b/runtime/arch/arm/portable_entrypoints_arm.S
index 3491c18..d37e760 100644
--- a/runtime/arch/arm/portable_entrypoints_arm.S
+++ b/runtime/arch/arm/portable_entrypoints_arm.S
@@ -53,7 +53,7 @@
     mov    ip, #0                          @ set ip to 0
     str    ip, [sp]                        @ store NULL for method* at bottom of frame
     add    sp, #16                         @ first 4 args are not passed on stack for portable
-    ldr    ip, [r0, #METHOD_PORTABLE_CODE_OFFSET]  @ get pointer to the code
+    ldr    ip, [r0, #MIRROR_ART_METHOD_PORTABLE_CODE_OFFSET]  @ get pointer to the code
     blx    ip                              @ call the method
     mov    sp, r11                         @ restore the stack pointer
     ldr    ip, [sp, #24]                   @ load the result pointer
@@ -138,7 +138,7 @@
 END art_portable_resolution_trampoline
 
     .extern artPortableToInterpreterBridge
-ENTRY_NO_HIDE art_portable_to_interpreter_bridge
+ENTRY art_portable_to_interpreter_bridge
     @ Fake callee save ref and args frame set up, note portable doesn't use callee save frames.
     @ TODO: just save the registers that are needed in artPortableToInterpreterBridge.
     push {r1-r3, r5-r8, r10-r11, lr}  @ 10 words of callee saves
@@ -165,3 +165,5 @@
     .cfi_adjust_cfa_offset -48
     bx      lr                     @ return
 END art_portable_to_interpreter_bridge
+
+UNIMPLEMENTED art_portable_imt_conflict_trampoline
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 466e9eb..aae0c94 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -27,8 +27,8 @@
      * Macro that sets up the callee save frame to conform with
      * Runtime::CreateCalleeSaveMethod(kSaveAll)
      */
-.macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
-    push {r4-r11, lr} @ 9 words of callee saves
+.macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME rTemp1, rTemp2
+    push {r4-r11, lr}                             @ 9 words (36 bytes) of callee saves.
     .save {r4-r11, lr}
     .cfi_adjust_cfa_offset 36
     .cfi_rel_offset r4, 0
@@ -40,12 +40,17 @@
     .cfi_rel_offset r10, 24
     .cfi_rel_offset r11, 28
     .cfi_rel_offset lr, 32
-    vpush {s0-s31}
+    vpush {s0-s31}                                @ 32 words (128 bytes) of floats.
     .pad #128
     .cfi_adjust_cfa_offset 128
-    sub sp, #12       @ 3 words of space, bottom word will hold Method*
+    sub sp, #12                                   @ 3 words of space, bottom word will hold Method*.
     .pad #12
     .cfi_adjust_cfa_offset 12
+    RUNTIME_CURRENT1 \rTemp1, \rTemp2             @ Load Runtime::Current into rTemp1.
+    THIS_LOAD_REQUIRES_READ_BARRIER
+    ldr \rTemp1, [\rTemp1, #RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET] @ rTemp1 is kSaveAll Method*.
+    str \rTemp1, [sp, #0]                         @ Place Method* at bottom of stack.
+    str sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET]  @ Place sp in Thread::Current()->top_quick_frame.
 
      // Ugly compile-time check, but we only have the preprocessor.
 #if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 36 + 128 + 12)
@@ -57,8 +62,8 @@
      * Macro that sets up the callee save frame to conform with
      * Runtime::CreateCalleeSaveMethod(kRefsOnly).
      */
-.macro SETUP_REF_ONLY_CALLEE_SAVE_FRAME
-    push {r5-r8, r10-r11, lr} @ 7 words of callee saves
+.macro SETUP_REFS_ONLY_CALLEE_SAVE_FRAME rTemp1, rTemp2
+    push {r5-r8, r10-r11, lr}                     @ 7 words of callee saves
     .save {r5-r8, r10-r11, lr}
     .cfi_adjust_cfa_offset 28
     .cfi_rel_offset r5, 0
@@ -68,9 +73,14 @@
     .cfi_rel_offset r10, 16
     .cfi_rel_offset r11, 20
     .cfi_rel_offset lr, 24
-    sub sp, #4                @ bottom word will hold Method*
+    sub sp, #4                                    @ bottom word will hold Method*
     .pad #4
     .cfi_adjust_cfa_offset 4
+    RUNTIME_CURRENT2 \rTemp1, \rTemp2             @ Load Runtime::Current into rTemp1.
+    THIS_LOAD_REQUIRES_READ_BARRIER
+    ldr \rTemp1, [\rTemp1, #RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET] @ rTemp1 is kRefsOnly Method*.
+    str \rTemp1, [sp, #0]                         @ Place Method* at bottom of stack.
+    str sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET]  @ Place sp in Thread::Current()->top_quick_frame.
 
     // Ugly compile-time check, but we only have the preprocessor.
 #if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 28 + 4)
@@ -78,7 +88,7 @@
 #endif
 .endm
 
-.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+.macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     add sp, #4               @ bottom word holds Method*
     pop {r5-r8, r10-r11, lr} @ 7 words of callee saves
     .cfi_restore r5
@@ -87,10 +97,10 @@
     .cfi_restore r8
     .cfi_restore r10
     .cfi_restore r11
-    .cfi_adjust_cfa_offset -32
+    .cfi_adjust_cfa_offset -FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
 .endm
 
-.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
+.macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
     add sp, #4               @ bottom word holds Method*
     pop {r5-r8, r10-r11, lr} @ 7 words of callee saves
     .cfi_restore r5
@@ -99,7 +109,7 @@
     .cfi_restore r8
     .cfi_restore r10
     .cfi_restore r11
-    .cfi_adjust_cfa_offset -32
+    .cfi_adjust_cfa_offset -FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
     bx  lr                   @ return
 .endm
 
@@ -107,8 +117,8 @@
      * Macro that sets up the callee save frame to conform with
      * Runtime::CreateCalleeSaveMethod(kRefsAndArgs).
      */
-.macro SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    push {r1-r3, r5-r8, r10-r11, lr}  @ 10 words of callee saves
+.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME rTemp1, rTemp2
+    push {r1-r3, r5-r8, r10-r11, lr}   @ 10 words of callee saves
     .save {r1-r3, r5-r8, r10-r11, lr}
     .cfi_rel_offset r1, 0
     .cfi_rel_offset r2, 4
@@ -121,9 +131,15 @@
     .cfi_rel_offset r11, 32
     .cfi_rel_offset lr, 36
     .cfi_adjust_cfa_offset 40
-    sub sp, #8                        @ 2 words of space, bottom word will hold Method*
+    sub sp, #8                         @ 2 words of space, bottom word will hold Method*
     .pad #8
     .cfi_adjust_cfa_offset 8
+    RUNTIME_CURRENT3 \rTemp1, \rTemp2  @ Load Runtime::Current into rTemp1.
+    THIS_LOAD_REQUIRES_READ_BARRIER
+     @ rTemp1 is kRefsAndArgs Method*.
+    ldr \rTemp1, [\rTemp1, #RUNTIME_REFS_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET]
+    str \rTemp1, [sp, #0]                         @ Place Method* at bottom of stack.
+    str sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET]  @ Place sp in Thread::Current()->top_quick_frame.
 
     // Ugly compile-time check, but we only have the preprocessor.
 #if (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE != 40 + 8)
@@ -131,7 +147,29 @@
 #endif
 .endm
 
-.macro RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_R0
+    push {r1-r3, r5-r8, r10-r11, lr}   @ 10 words of callee saves
+    .save {r1-r3, r5-r8, r10-r11, lr}
+    .cfi_rel_offset r1, 0
+    .cfi_rel_offset r2, 4
+    .cfi_rel_offset r3, 8
+    .cfi_rel_offset r5, 12
+    .cfi_rel_offset r6, 16
+    .cfi_rel_offset r7, 20
+    .cfi_rel_offset r8, 24
+    .cfi_rel_offset r10, 28
+    .cfi_rel_offset r11, 32
+    .cfi_rel_offset lr, 36
+    .cfi_adjust_cfa_offset 40
+    sub sp, #8                         @ 2 words of space, bottom word will hold Method*
+    .pad #8
+    .cfi_adjust_cfa_offset 8
+
+    str r0, [sp, #0]                   @ Store ArtMethod* to bottom of stack.
+    str sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET]  @ Place sp in Thread::Current()->top_quick_frame.
+.endm
+
+.macro RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     add  sp, #8                      @ rewind sp
     pop {r1-r3, r5-r8, r10-r11, lr}  @ 10 words of callee saves
     .cfi_restore r1
@@ -146,6 +184,7 @@
     .cfi_adjust_cfa_offset -48
 .endm
 
+
 .macro RETURN_IF_RESULT_IS_ZERO
     cbnz   r0, 1f              @ result non-zero branch over
     bx     lr                  @ return
@@ -165,41 +204,35 @@
 .macro DELIVER_PENDING_EXCEPTION
     .fnend
     .fnstart
-    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME           @ save callee saves for throw
+    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME r0, r1    @ save callee saves for throw
     mov    r0, r9                              @ pass Thread::Current
-    mov    r1, sp                              @ pass SP
-    b      artDeliverPendingExceptionFromCode  @ artDeliverPendingExceptionFromCode(Thread*, SP)
+    b      artDeliverPendingExceptionFromCode  @ artDeliverPendingExceptionFromCode(Thread*)
 .endm
 
 .macro NO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
     .extern \cxx_name
 ENTRY \c_name
-    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
+    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  r0, r1 // save all registers as basis for long jump context
     mov r0, r9                      @ pass Thread::Current
-    mov r1, sp                      @ pass SP
-    b   \cxx_name                   @ \cxx_name(Thread*, SP)
+    b   \cxx_name                   @ \cxx_name(Thread*)
 END \c_name
 .endm
 
 .macro ONE_ARG_RUNTIME_EXCEPTION c_name, cxx_name
     .extern \cxx_name
 ENTRY \c_name
-    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
+    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME r1, r2  // save all registers as basis for long jump context
     mov r1, r9                      @ pass Thread::Current
-    mov r2, sp                      @ pass SP
-    b   \cxx_name                   @ \cxx_name(Thread*, SP)
-    bkpt
+    b   \cxx_name                   @ \cxx_name(Thread*)
 END \c_name
 .endm
 
 .macro TWO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
     .extern \cxx_name
 ENTRY \c_name
-    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
+    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  r2, r3  // save all registers as basis for long jump context
     mov r2, r9                      @ pass Thread::Current
-    mov r3, sp                      @ pass SP
-    b   \cxx_name                   @ \cxx_name(Thread*, SP)
-    bkpt
+    b   \cxx_name                   @ \cxx_name(Thread*)
 END \c_name
 .endm
 
@@ -224,12 +257,11 @@
 .macro  ONE_ARG_REF_DOWNCALL name, entrypoint, return
     .extern \entrypoint
 ENTRY \name
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
-    ldr    r1, [sp, #32]                 @ pass referrer
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r1, r2  @ save callee saves in case of GC
+    ldr    r1, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE]  @ pass referrer
     mov    r2, r9                        @ pass Thread::Current
-    mov    r3, sp                        @ pass SP
-    bl     \entrypoint                   @ (uint32_t field_idx, const Method* referrer, Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    bl     \entrypoint                   @ (uint32_t field_idx, const Method* referrer, Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     \return
 END \name
 .endm
@@ -237,17 +269,11 @@
 .macro  TWO_ARG_REF_DOWNCALL name, entrypoint, return
     .extern \entrypoint
 ENTRY \name
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
-    ldr    r2, [sp, #32]                 @ pass referrer
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r2, r3  @ save callee saves in case of GC
+    ldr    r2, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE]  @ pass referrer
     mov    r3, r9                        @ pass Thread::Current
-    mov    r12, sp
-    str    r12, [sp, #-16]!              @ expand the frame and pass SP
-    .pad #16
-    .cfi_adjust_cfa_offset 16
-    bl     \entrypoint                   @ (field_idx, Object*, referrer, Thread*, SP)
-    add    sp, #16                       @ strip the extra frame
-    .cfi_adjust_cfa_offset -16
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    bl     \entrypoint                   @ (field_idx, Object*, referrer, Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     \return
 END \name
 .endm
@@ -255,21 +281,15 @@
 .macro  THREE_ARG_REF_DOWNCALL name, entrypoint, return
     .extern \entrypoint
 ENTRY \name
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
-    ldr    r3, [sp, #32]                 @ pass referrer
-    mov    r12, sp                       @ save SP
-    sub    sp, #8                        @ grow frame for alignment with stack args
-    .pad #8
-    .cfi_adjust_cfa_offset 8
-    push   {r9, r12}                     @ pass Thread::Current and SP
-    .save {r9, r12}
-    .cfi_adjust_cfa_offset 8
-    .cfi_rel_offset r9, 0
-    .cfi_rel_offset r12, 4
-    bl     \entrypoint                   @ (field_idx, Object*, new_val, referrer, Thread*, SP)
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r3, r12  @ save callee saves in case of GC
+    ldr    r3, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE]  @ pass referrer
+    str    r9, [sp, #-16]!               @ expand the frame and pass Thread::Current
+    .pad #16
+    .cfi_adjust_cfa_offset 16
+    bl     \entrypoint                   @ (field_idx, Object*, new_val, referrer, Thread*)
     add    sp, #16                       @ release out args
     .cfi_adjust_cfa_offset -16
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME   @ TODO: we can clearly save an add here
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME   @ TODO: we can clearly save an add here
     \return
 END \name
 .endm
@@ -325,8 +345,8 @@
 .macro INVOKE_TRAMPOLINE c_name, cxx_name
     .extern \cxx_name
 ENTRY \c_name
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME  @ save callee saves in case allocation triggers GC
-    ldr    r2, [sp, #48]                  @ pass caller Method*
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME r2, r3  @ save callee saves in case allocation triggers GC
+    ldr    r2, [sp, #FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE]  @ pass caller Method*
     mov    r3, r9                         @ pass Thread::Current
     mov    r12, sp
     str    r12, [sp, #-16]!               @ expand the frame and pass SP
@@ -336,7 +356,7 @@
     add    sp, #16                        @ strip the extra frame
     .cfi_adjust_cfa_offset -16
     mov    r12, r1                        @ save Method*->code_
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     cbz    r0, 1f                         @ did we find the target? if not go to exception delivery
     bx     r12                            @ tail call to target
 1:
@@ -393,7 +413,7 @@
     ldr    r3, [sp, #12]                   @ copy arg value for r3
     mov    ip, #0                          @ set ip to 0
     str    ip, [sp]                        @ store NULL for method* at bottom of frame
-    ldr    ip, [r0, #METHOD_QUICK_CODE_OFFSET]  @ get pointer to the code
+    ldr    ip, [r0, #MIRROR_ART_METHOD_QUICK_CODE_OFFSET]  @ get pointer to the code
     blx    ip                              @ call the method
     mov    sp, r11                         @ restore the stack pointer
     ldr    ip, [sp, #24]                   @ load the result pointer
@@ -437,10 +457,10 @@
     cbz    r0, .Lslow_lock
 .Lretry_lock:
     ldr    r2, [r9, #THREAD_ID_OFFSET]
-    ldrex  r1, [r0, #LOCK_WORD_OFFSET]
+    ldrex  r1, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET]
     cbnz   r1, .Lnot_unlocked         @ already thin locked
     @ unlocked case - r2 holds thread id with count of 0
-    strex  r3, r2, [r0, #LOCK_WORD_OFFSET]
+    strex  r3, r2, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET]
     cbnz   r3, .Lstrex_fail           @ store failed, retry
     dmb    ish                        @ full (LoadLoad|LoadStore) memory barrier
     bx lr
@@ -456,14 +476,13 @@
     add    r2, r1, #65536             @ increment count in lock word placing in r2 for storing
     lsr    r1, r2, 30                 @ if either of the top two bits are set, we overflowed.
     cbnz   r1, .Lslow_lock            @ if we overflow the count go slow path
-    str    r2, [r0, #LOCK_WORD_OFFSET] @ no need for strex as we hold the lock
+    str    r2, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] @ no need for strex as we hold the lock
     bx lr
 .Lslow_lock:
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case we block
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r1, r2  @ save callee saves in case we block
     mov    r1, r9                     @ pass Thread::Current
-    mov    r2, sp                     @ pass SP
-    bl     artLockObjectFromCode      @ (Object* obj, Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    bl     artLockObjectFromCode      @ (Object* obj, Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     RETURN_IF_RESULT_IS_ZERO
     DELIVER_PENDING_EXCEPTION
 END art_quick_lock_object
@@ -475,7 +494,7 @@
     .extern artUnlockObjectFromCode
 ENTRY art_quick_unlock_object
     cbz    r0, .Lslow_unlock
-    ldr    r1, [r0, #LOCK_WORD_OFFSET]
+    ldr    r1, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET]
     lsr    r2, r1, 30
     cbnz   r2, .Lslow_unlock          @ if either of the top two bits are set, go slow path
     ldr    r2, [r9, #THREAD_ID_OFFSET]
@@ -486,18 +505,18 @@
     bpl    .Lrecursive_thin_unlock
     @ transition to unlocked, r3 holds 0
     dmb    ish                        @ full (LoadStore|StoreStore) memory barrier
-    str    r3, [r0, #LOCK_WORD_OFFSET]
+    str    r3, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET]
     bx     lr
 .Lrecursive_thin_unlock:
     sub    r1, r1, #65536
-    str    r1, [r0, #LOCK_WORD_OFFSET]
+    str    r1, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET]
     bx     lr
 .Lslow_unlock:
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case exception allocation triggers GC
+    @ save callee saves in case exception allocation triggers GC
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r1, r2
     mov    r1, r9                     @ pass Thread::Current
-    mov    r2, sp                     @ pass SP
-    bl     artUnlockObjectFromCode    @ (Object* obj, Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    bl     artUnlockObjectFromCode    @ (Object* obj, Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     RETURN_IF_RESULT_IS_ZERO
     DELIVER_PENDING_EXCEPTION
 END art_quick_unlock_object
@@ -528,10 +547,9 @@
     pop {r0-r1, lr}
     .cfi_restore r0
     .cfi_restore r1
-    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
+    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME r2, r3  // save all registers as basis for long jump context
     mov r2, r9                      @ pass Thread::Current
-    mov r3, sp                      @ pass SP
-    b   artThrowClassCastException  @ (Class*, Class*, Thread*, SP)
+    b   artThrowClassCastException  @ (Class*, Class*, Thread*)
     bkpt
 END art_quick_check_cast
 
@@ -548,7 +566,7 @@
 
     .hidden art_quick_aput_obj_with_bound_check
 ENTRY art_quick_aput_obj_with_bound_check
-    ldr r3, [r0, #ARRAY_LENGTH_OFFSET]
+    ldr r3, [r0, #MIRROR_ARRAY_LENGTH_OFFSET]
     cmp r3, r1
     bhi art_quick_aput_obj
     mov r0, r1
@@ -559,20 +577,20 @@
     .hidden art_quick_aput_obj
 ENTRY art_quick_aput_obj
     cbz r2, .Ldo_aput_null
-    ldr r3, [r0, #CLASS_OFFSET]
-    ldr ip, [r2, #CLASS_OFFSET]
-    ldr r3, [r3, #CLASS_COMPONENT_TYPE_OFFSET]
+    ldr r3, [r0, #MIRROR_OBJECT_CLASS_OFFSET]
+    ldr ip, [r2, #MIRROR_OBJECT_CLASS_OFFSET]
+    ldr r3, [r3, #MIRROR_CLASS_COMPONENT_TYPE_OFFSET]
     cmp r3, ip  @ value's type == array's component type - trivial assignability
     bne .Lcheck_assignability
 .Ldo_aput:
-    add r3, r0, #OBJECT_ARRAY_DATA_OFFSET
+    add r3, r0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET
     str r2, [r3, r1, lsl #2]
     ldr r3, [r9, #THREAD_CARD_TABLE_OFFSET]
     lsr r0, r0, #7
     strb r3, [r3, r0]
     blx lr
 .Ldo_aput_null:
-    add r3, r0, #OBJECT_ARRAY_DATA_OFFSET
+    add r3, r0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET
     str r2, [r3, r1, lsl #2]
     blx lr
 .Lcheck_assignability:
@@ -593,7 +611,7 @@
     .cfi_restore r2
     .cfi_restore lr
     .cfi_adjust_cfa_offset -16
-    add r3, r0, #OBJECT_ARRAY_DATA_OFFSET
+    add r3, r0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET
     str r2, [r3, r1, lsl #2]
     ldr r3, [r9, #THREAD_CARD_TABLE_OFFSET]
     lsr r0, r0, #7
@@ -606,12 +624,11 @@
     .cfi_restore r2
     .cfi_restore lr
     .cfi_adjust_cfa_offset -16
-    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
+    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME r3, ip
     mov r1, r2
-    mov r2, r9                   @ pass Thread::Current
-    mov r3, sp                   @ pass SP
-    b artThrowArrayStoreException  @ (Class*, Class*, Thread*, SP)
-    bkpt                         @ unreached
+    mov r2, r9                     @ pass Thread::Current
+    b artThrowArrayStoreException  @ (Class*, Class*, Thread*)
+    bkpt                           @ unreached
 END art_quick_aput_obj
 
     /*
@@ -621,12 +638,11 @@
      */
     .extern artInitializeStaticStorageFromCode
 ENTRY art_quick_initialize_static_storage
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME           @ save callee saves in case of GC
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r2, r3    @ save callee saves in case of GC
     mov    r2, r9                              @ pass Thread::Current
-    mov    r3, sp                              @ pass SP
-    @ artInitializeStaticStorageFromCode(uint32_t type_idx, Method* referrer, Thread*, SP)
+    @ artInitializeStaticStorageFromCode(uint32_t type_idx, Method* referrer, Thread*)
     bl     artInitializeStaticStorageFromCode
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     RETURN_IF_RESULT_IS_NON_ZERO
     DELIVER_PENDING_EXCEPTION
 END art_quick_initialize_static_storage
@@ -636,12 +652,11 @@
      */
     .extern artInitializeTypeFromCode
 ENTRY art_quick_initialize_type
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME           @ save callee saves in case of GC
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r2, r3    @ save callee saves in case of GC
     mov    r2, r9                              @ pass Thread::Current
-    mov    r3, sp                              @ pass SP
-    @ artInitializeTypeFromCode(uint32_t type_idx, Method* referrer, Thread*, SP)
+    @ artInitializeTypeFromCode(uint32_t type_idx, Method* referrer, Thread*)
     bl     artInitializeTypeFromCode
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     RETURN_IF_RESULT_IS_NON_ZERO
     DELIVER_PENDING_EXCEPTION
 END art_quick_initialize_type
@@ -652,12 +667,11 @@
      */
     .extern artInitializeTypeAndVerifyAccessFromCode
 ENTRY art_quick_initialize_type_and_verify_access
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME           @ save callee saves in case of GC
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r2, r3    @ save callee saves in case of GC
     mov    r2, r9                              @ pass Thread::Current
-    mov    r3, sp                              @ pass SP
-    @ artInitializeTypeAndVerifyAccessFromCode(uint32_t type_idx, Method* referrer, Thread*, SP)
+    @ artInitializeTypeAndVerifyAccessFromCode(uint32_t type_idx, Method* referrer, Thread*)
     bl     artInitializeTypeAndVerifyAccessFromCode
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     RETURN_IF_RESULT_IS_NON_ZERO
     DELIVER_PENDING_EXCEPTION
 END art_quick_initialize_type_and_verify_access
@@ -676,13 +690,12 @@
      */
     .extern artGet64StaticFromCode
 ENTRY art_quick_get64_static
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
-    ldr    r1, [sp, #32]                 @ pass referrer
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r2, r3  @ save callee saves in case of GC
+    ldr    r1, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE]  @ pass referrer
     mov    r2, r9                        @ pass Thread::Current
-    mov    r3, sp                        @ pass SP
-    bl     artGet64StaticFromCode        @ (uint32_t field_idx, const Method* referrer, Thread*, SP)
+    bl     artGet64StaticFromCode        @ (uint32_t field_idx, const Method* referrer, Thread*)
     ldr    r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     cbnz   r2, 1f                        @ success if no exception pending
     bx     lr                            @ return on success
 1:
@@ -703,18 +716,12 @@
      */
     .extern artGet64InstanceFromCode
 ENTRY art_quick_get64_instance
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
-    ldr    r2, [sp, #32]                 @ pass referrer
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  r2, r3  @ save callee saves in case of GC
+    ldr    r2, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE]  @ pass referrer
     mov    r3, r9                        @ pass Thread::Current
-    mov    r12, sp
-    str    r12, [sp, #-16]!              @ expand the frame and pass SP
-    .pad #16
-    .cfi_adjust_cfa_offset 16
-    bl     artGet64InstanceFromCode      @ (field_idx, Object*, referrer, Thread*, SP)
-    add    sp, #16                       @ strip the extra frame
-    .cfi_adjust_cfa_offset -16
+    bl     artGet64InstanceFromCode      @ (field_idx, Object*, referrer, Thread*)
     ldr    r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     cbnz   r2, 1f                        @ success if no exception pending
     bx     lr                            @ return on success
 1:
@@ -734,22 +741,17 @@
      */
     .extern artSet64StaticFromCode
 ENTRY art_quick_set64_static
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r3, r12   @ save callee saves in case of GC
     mov    r3, r2                        @ pass one half of wide argument
     mov    r2, r1                        @ pass other half of wide argument
-    ldr    r1, [sp, #32]                 @ pass referrer
-    mov    r12, sp                       @ save SP
-    sub    sp, #8                        @ grow frame for alignment with stack args
-    .pad #8
-    .cfi_adjust_cfa_offset 8
-    push   {r9, r12}                     @ pass Thread::Current and SP
-    .save {r9, r12}
-    .cfi_adjust_cfa_offset 8
-    .cfi_rel_offset r9, 0
-    bl     artSet64StaticFromCode        @ (field_idx, referrer, new_val, Thread*, SP)
+    ldr    r1, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE]  @ pass referrer
+    str    r9, [sp, #-16]!               @ expand the frame and pass Thread::Current
+    .pad #16
+    .cfi_adjust_cfa_offset 16
+    bl     artSet64StaticFromCode        @ (field_idx, referrer, new_val, Thread*)
     add    sp, #16                       @ release out args
     .cfi_adjust_cfa_offset -16
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME   @ TODO: we can clearly save an add here
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME  @ TODO: we can clearly save an add here
     RETURN_IF_RESULT_IS_ZERO
     DELIVER_PENDING_EXCEPTION
 END art_quick_set64_static
@@ -766,19 +768,18 @@
      */
     .extern artSet64InstanceFromCode
 ENTRY art_quick_set64_instance
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
-    mov    r12, sp                       @ save SP
-    sub    sp, #8                        @ grow frame for alignment with stack args
-    .pad #8
-    .cfi_adjust_cfa_offset 8
-    push   {r9, r12}                     @ pass Thread::Current and SP
-    .save {r9, r12}
-    .cfi_adjust_cfa_offset 8
-    .cfi_rel_offset r9, 0
-    bl     artSet64InstanceFromCode      @ (field_idx, Object*, new_val, Thread*, SP)
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r12, lr  @ save callee saves in case of GC
+    ldr    r12, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE]  @ pass referrer
+    str    r9, [sp, #-12]!               @ expand the frame and pass Thread::Current
+    .pad #12
+    .cfi_adjust_cfa_offset 12
+    str    r12, [sp, #-4]!               @ expand the frame and pass the referrer
+    .pad #4
+    .cfi_adjust_cfa_offset 4
+    bl     artSet64InstanceFromCode      @ (field_idx, Object*, new_val, Method* referrer, Thread*)
     add    sp, #16                       @ release out args
     .cfi_adjust_cfa_offset -16
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME   @ TODO: we can clearly save an add here
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME  @ TODO: we can clearly save an add here
     RETURN_IF_RESULT_IS_ZERO
     DELIVER_PENDING_EXCEPTION
 END art_quick_set64_instance
@@ -791,12 +792,11 @@
      */
     .extern artResolveStringFromCode
 ENTRY art_quick_resolve_string
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case of GC
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r2, r3  @ save callee saves in case of GC
     mov    r2, r9                     @ pass Thread::Current
-    mov    r3, sp                     @ pass SP
-    @ artResolveStringFromCode(Method* referrer, uint32_t string_idx, Thread*, SP)
+    @ artResolveStringFromCode(Method* referrer, uint32_t string_idx, Thread*)
     bl     artResolveStringFromCode
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     RETURN_IF_RESULT_IS_NON_ZERO
     DELIVER_PENDING_EXCEPTION
 END art_quick_resolve_string
@@ -805,11 +805,10 @@
 .macro TWO_ARG_DOWNCALL name, entrypoint, return
     .extern \entrypoint
 ENTRY \name
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case of GC
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  r2, r3  @ save callee saves in case of GC
     mov    r2, r9                     @ pass Thread::Current
-    mov    r3, sp                     @ pass SP
-    bl     \entrypoint     @ (uint32_t type_idx, Method* method, Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    bl     \entrypoint     @ (uint32_t type_idx, Method* method, Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     \return
     DELIVER_PENDING_EXCEPTION
 END \name
@@ -819,17 +818,11 @@
 .macro THREE_ARG_DOWNCALL name, entrypoint, return
     .extern \entrypoint
 ENTRY \name
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case of GC
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  r3, r12  @ save callee saves in case of GC
     mov    r3, r9                     @ pass Thread::Current
-    mov    r12, sp
-    str    r12, [sp, #-16]!           @ expand the frame and pass SP
-    .pad #16
-    .cfi_adjust_cfa_offset 16
-    @ (uint32_t type_idx, Method* method, int32_t component_count, Thread*, SP)
+    @ (uint32_t type_idx, Method* method, int32_t component_count, Thread*)
     bl     \entrypoint
-    add    sp, #16                    @ strip the extra frame
-    .cfi_adjust_cfa_offset -16
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     \return
     DELIVER_PENDING_EXCEPTION
 END \name
@@ -844,25 +837,24 @@
     .extern artTestSuspendFromCode
 ENTRY art_quick_test_suspend
 #ifdef ARM_R4_SUSPEND_FLAG
-    ldrh    r0, [rSELF, #THREAD_FLAGS_OFFSET]
+    ldrh   r0, [rSELF, #THREAD_FLAGS_OFFSET]
     mov    rSUSPEND, #SUSPEND_CHECK_INTERVAL  @ reset rSUSPEND to SUSPEND_CHECK_INTERVAL
     cbnz   r0, 1f                             @ check Thread::Current()->suspend_count_ == 0
     bx     lr                                 @ return if suspend_count_ == 0
 1:
 #endif
     mov    r0, rSELF
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME          @ save callee saves for stack crawl
-    mov    r1, sp
-    bl     artTestSuspendFromCode             @ (Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r1, r2   @ save callee saves for GC stack crawl
+    @ TODO: save FPRs to enable access in the debugger?
+    bl     artTestSuspendFromCode             @ (Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
 END art_quick_test_suspend
 
 ENTRY art_quick_implicit_suspend
     mov    r0, rSELF
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME          @ save callee saves for stack crawl
-    mov    r1, sp
-    bl     artTestSuspendFromCode             @ (Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r1, r2   @ save callee saves for stack crawl
+    bl     artTestSuspendFromCode             @ (Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
 END art_quick_implicit_suspend
 
     /*
@@ -872,8 +864,7 @@
      */
      .extern artQuickProxyInvokeHandler
 ENTRY art_quick_proxy_invoke_handler
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    str     r0, [sp, #0]           @ place proxy method at bottom of frame
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_R0
     mov     r2, r9                 @ pass Thread::Current
     mov     r3, sp                 @ pass SP
     blx     artQuickProxyInvokeHandler  @ (Method* proxy method, receiver, Thread*, SP)
@@ -881,10 +872,10 @@
     add     sp, #16                @ skip r1-r3, 4 bytes padding.
     .cfi_adjust_cfa_offset -16
     cbnz    r2, 1f                 @ success if no exception is pending
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     bx      lr                     @ return on success
 1:
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     DELIVER_PENDING_EXCEPTION
 END art_quick_proxy_invoke_handler
 
@@ -894,34 +885,33 @@
      */
 ENTRY art_quick_imt_conflict_trampoline
     ldr    r0, [sp, #0]            @ load caller Method*
-    ldr    r0, [r0, #METHOD_DEX_CACHE_METHODS_OFFSET]  @ load dex_cache_resolved_methods
-    add    r0, #OBJECT_ARRAY_DATA_OFFSET  @ get starting address of data
+    ldr    r0, [r0, #MIRROR_ART_METHOD_DEX_CACHE_METHODS_OFFSET]  @ load dex_cache_resolved_methods
+    add    r0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET  @ get starting address of data
     ldr    r0, [r0, r12, lsl 2]    @ load the target method
     b art_quick_invoke_interface_trampoline
 END art_quick_imt_conflict_trampoline
 
     .extern artQuickResolutionTrampoline
 ENTRY art_quick_resolution_trampoline
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME r2, r3
     mov     r2, r9                 @ pass Thread::Current
     mov     r3, sp                 @ pass SP
     blx     artQuickResolutionTrampoline  @ (Method* called, receiver, Thread*, SP)
     cbz     r0, 1f                 @ is code pointer null? goto exception
     mov     r12, r0
     ldr  r0, [sp, #0]              @ load resolved method in r0
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     bx      r12                    @ tail-call into actual code
 1:
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     DELIVER_PENDING_EXCEPTION
 END art_quick_resolution_trampoline
 
     /*
      * Called to do a generic JNI down-call
      */
-ENTRY_NO_HIDE art_quick_generic_jni_trampoline
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    str r0, [sp, #0]  // Store native ArtMethod* to bottom of stack.
+ENTRY art_quick_generic_jni_trampoline
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_R0
 
     // Save rSELF
     mov r11, rSELF
@@ -1008,21 +998,21 @@
     .cfi_def_cfa_register sp
     mov r9, r11
 .Lexception_in_native:
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     DELIVER_PENDING_EXCEPTION
 
 END art_quick_generic_jni_trampoline
 
     .extern artQuickToInterpreterBridge
-ENTRY_NO_HIDE art_quick_to_interpreter_bridge
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
+ENTRY art_quick_to_interpreter_bridge
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME r1, r2
     mov     r1, r9                 @ pass Thread::Current
     mov     r2, sp                 @ pass SP
     blx     artQuickToInterpreterBridge    @ (Method* method, Thread*, SP)
     ldr     r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
     add     sp, #16                @ skip r1-r3, 4 bytes padding.
     .cfi_adjust_cfa_offset -16
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     cbnz    r2, 1f                 @ success if no exception is pending
     bx    lr                       @ return on success
 1:
@@ -1035,30 +1025,23 @@
     .extern artInstrumentationMethodEntryFromCode
     .extern artInstrumentationMethodExitFromCode
 ENTRY art_quick_instrumentation_entry
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    str   r0, [sp, #4]     @ preserve r0
-    mov   r12, sp          @ remember sp
-    str   lr, [sp, #-16]!  @ expand the frame and pass LR
-    .pad #16
-    .cfi_adjust_cfa_offset 16
-    .cfi_rel_offset lr, 0
+    @ Make stack crawlable and clobber r2 and r3 (post saving)
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME r2, r3
+    @ preserve r0 (not normally an arg) knowing there is a spare slot in kRefsAndArgs.
+    str   r0, [sp, #4]
     mov   r2, r9         @ pass Thread::Current
-    mov   r3, r12        @ pass SP
-    blx   artInstrumentationMethodEntryFromCode  @ (Method*, Object*, Thread*, SP, LR)
-    add   sp, #16        @ remove out argument and padding from stack
-    .cfi_adjust_cfa_offset -16
+    mov   r3, lr         @ pass LR
+    blx   artInstrumentationMethodEntryFromCode  @ (Method*, Object*, Thread*, LR)
     mov   r12, r0        @ r12 holds reference to code
     ldr   r0, [sp, #4]   @ restore r0
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     blx   r12            @ call method with lr set to art_quick_instrumentation_exit
-END art_quick_instrumentation_entry
+@ Deliberate fall-through into art_quick_instrumentation_exit.
     .type art_quick_instrumentation_exit, #function
     .global art_quick_instrumentation_exit
 art_quick_instrumentation_exit:
-    .cfi_startproc
-    .fnstart
     mov   lr, #0         @ link register is to here, so clobber with 0 for later checks
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r2, r3  @ set up frame knowing r2 and r3 must be dead on exit
     mov   r12, sp        @ remember bottom of caller's frame
     push  {r0-r1}        @ save return value
     .save {r0-r1}
@@ -1085,7 +1068,7 @@
     add sp, #32          @ remove callee save frame
     .cfi_adjust_cfa_offset -32
     bx    r2             @ return
-END art_quick_instrumentation_exit
+END art_quick_instrumentation_entry
 
     /*
      * Instrumentation has requested that we deoptimize into the interpreter. The deoptimization
@@ -1093,10 +1076,9 @@
      */
     .extern artDeoptimize
 ENTRY art_quick_deoptimize
-    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
+    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME r0, r1
     mov    r0, r9         @ Set up args.
-    mov    r1, sp
-    blx    artDeoptimize  @ artDeoptimize(Thread*, SP)
+    blx    artDeoptimize  @ artDeoptimize(Thread*)
 END art_quick_deoptimize
 
     /*
@@ -1219,9 +1201,9 @@
     .cfi_rel_offset r10, 4
     .cfi_rel_offset r11, 8
     .cfi_rel_offset lr, 12
-    ldr   r3, [r0, #STRING_COUNT_OFFSET]
-    ldr   r12, [r0, #STRING_OFFSET_OFFSET]
-    ldr   r0, [r0, #STRING_VALUE_OFFSET]
+    ldr   r3, [r0, #MIRROR_STRING_COUNT_OFFSET]
+    ldr   r12, [r0, #MIRROR_STRING_OFFSET_OFFSET]
+    ldr   r0, [r0, #MIRROR_STRING_VALUE_OFFSET]
 
     /* Clamp start to [0..count] */
     cmp   r2, #0
@@ -1232,7 +1214,7 @@
     movgt r2, r3
 
     /* Build a pointer to the start of string data */
-    add   r0, #STRING_DATA_OFFSET
+    add   r0, #MIRROR_CHAR_ARRAY_DATA_OFFSET
     add   r0, r0, r12, lsl #1
 
     /* Save a copy in r12 to later compute result */
@@ -1341,12 +1323,12 @@
     .cfi_rel_offset r12, 24
     .cfi_rel_offset lr, 28
 
-    ldr    r4, [r2, #STRING_OFFSET_OFFSET]
-    ldr    r9, [r1, #STRING_OFFSET_OFFSET]
-    ldr    r7, [r2, #STRING_COUNT_OFFSET]
-    ldr    r10, [r1, #STRING_COUNT_OFFSET]
-    ldr    r2, [r2, #STRING_VALUE_OFFSET]
-    ldr    r1, [r1, #STRING_VALUE_OFFSET]
+    ldr    r4, [r2, #MIRROR_STRING_OFFSET_OFFSET]
+    ldr    r9, [r1, #MIRROR_STRING_OFFSET_OFFSET]
+    ldr    r7, [r2, #MIRROR_STRING_COUNT_OFFSET]
+    ldr    r10, [r1, #MIRROR_STRING_COUNT_OFFSET]
+    ldr    r2, [r2, #MIRROR_STRING_VALUE_OFFSET]
+    ldr    r1, [r1, #MIRROR_STRING_VALUE_OFFSET]
 
     /*
      * At this point, we have:
@@ -1368,8 +1350,8 @@
       * Note: data pointers point to previous element so we can use pre-index
       * mode with base writeback.
       */
-     add   r2, #STRING_DATA_OFFSET-2   @ offset to contents[-1]
-     add   r1, #STRING_DATA_OFFSET-2   @ offset to contents[-1]
+     add   r2, #MIRROR_CHAR_ARRAY_DATA_OFFSET-2   @ offset to contents[-1]
+     add   r1, #MIRROR_CHAR_ARRAY_DATA_OFFSET-2   @ offset to contents[-1]
 
      /*
       * At this point we have:
diff --git a/runtime/arch/arm64/asm_support_arm64.S b/runtime/arch/arm64/asm_support_arm64.S
index fb49460..b3e9242 100644
--- a/runtime/arch/arm64/asm_support_arm64.S
+++ b/runtime/arch/arm64/asm_support_arm64.S
@@ -52,15 +52,6 @@
     .cfi_startproc
 .endm
 
-.macro ENTRY_NO_HIDE name
-    .type \name, #function
-    .global \name
-    /* Cache alignment for function entry */
-    .balign 16
-\name:
-    .cfi_startproc
-.endm
-
 .macro END name
     .cfi_endproc
     .size \name, .-\name
@@ -72,10 +63,4 @@
     END \name
 .endm
 
-.macro UNIMPLEMENTED_NO_HIDE name
-    ENTRY_NO_HIDE \name
-    brk 0
-    END \name
-.endm
-
 #endif  // ART_RUNTIME_ARCH_ARM64_ASM_SUPPORT_ARM64_S_
diff --git a/runtime/arch/arm64/asm_support_arm64.h b/runtime/arch/arm64/asm_support_arm64.h
index a926449..989ecc6 100644
--- a/runtime/arch/arm64/asm_support_arm64.h
+++ b/runtime/arch/arm64/asm_support_arm64.h
@@ -19,30 +19,8 @@
 
 #include "asm_support.h"
 
-// Note: these callee save methods loads require read barriers.
-// Offset of field Runtime::callee_save_methods_[kSaveAll] verified in InitCpu
-#define RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET 0
-// Offset of field Runtime::callee_save_methods_[kRefsOnly] verified in InitCpu
-#define RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET 8
-// Offset of field Runtime::callee_save_methods_[kRefsAndArgs] verified in InitCpu
-#define RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET 16
-
-// Offset of field Thread::suspend_count_
-#define THREAD_FLAGS_OFFSET 0
-// Offset of field Thread::card_table_
-#define THREAD_CARD_TABLE_OFFSET 120
-// Offset of field Thread::exception_
-#define THREAD_EXCEPTION_OFFSET 128
-// Offset of field Thread::thin_lock_thread_id_
-#define THREAD_ID_OFFSET 12
-
 #define FRAME_SIZE_SAVE_ALL_CALLEE_SAVE 176
 #define FRAME_SIZE_REFS_ONLY_CALLEE_SAVE 96
 #define FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE 224
 
-// Expected size of a heap reference
-#define HEAP_REFERENCE_SIZE 4
-// Expected size of a stack reference
-#define STACK_REFERENCE_SIZE 4
-
 #endif  // ART_RUNTIME_ARCH_ARM64_ASM_SUPPORT_ARM64_H_
diff --git a/runtime/arch/arm64/context_arm64.cc b/runtime/arch/arm64/context_arm64.cc
index 3eb92c8..6aacda4 100644
--- a/runtime/arch/arm64/context_arm64.cc
+++ b/runtime/arch/arm64/context_arm64.cc
@@ -31,7 +31,7 @@
 static constexpr uint64_t gZero = 0;
 
 void Arm64Context::Reset() {
-  for (size_t i = 0; i < kNumberOfCoreRegisters; i++) {
+  for (size_t i = 0; i < kNumberOfXRegisters; i++) {
     gprs_[i] = nullptr;
   }
   for (size_t i = 0; i < kNumberOfDRegisters; i++) {
@@ -52,7 +52,7 @@
   if (spill_count > 0) {
     // Lowest number spill is farthest away, walk registers and fill into context.
     int j = 1;
-    for (size_t i = 0; i < kNumberOfCoreRegisters; i++) {
+    for (size_t i = 0; i < kNumberOfXRegisters; i++) {
       if (((frame_info.CoreSpillMask() >> i) & 1) != 0) {
         gprs_[i] = fr.CalleeSaveAddress(spill_count  - j, frame_info.FrameSizeInBytes());
         j++;
@@ -74,7 +74,8 @@
 }
 
 bool Arm64Context::SetGPR(uint32_t reg, uintptr_t value) {
-  DCHECK_LT(reg, static_cast<uint32_t>(kNumberOfCoreRegisters));
+  DCHECK_LT(reg, static_cast<uint32_t>(kNumberOfXRegisters));
+  DCHECK_NE(reg, static_cast<uint32_t>(XZR));
   DCHECK_NE(gprs_[reg], &gZero);  // Can't overwrite this static value since they are never reset.
   if (gprs_[reg] != nullptr) {
     *gprs_[reg] = value;
@@ -146,11 +147,13 @@
 extern "C" void art_quick_do_long_jump(uint64_t*, uint64_t*);
 
 void Arm64Context::DoLongJump() {
-  uint64_t gprs[32];
+  uint64_t gprs[kNumberOfXRegisters];
   uint64_t fprs[kNumberOfDRegisters];
 
-  // Do not use kNumberOfCoreRegisters, as this is with the distinction of SP and XZR
-  for (size_t i = 0; i < 32; ++i) {
+  // The long jump routine called below expects to find the value for SP at index 31.
+  DCHECK_EQ(SP, 31);
+
+  for (size_t i = 0; i < kNumberOfXRegisters; ++i) {
     gprs[i] = gprs_[i] != nullptr ? *gprs_[i] : Arm64Context::kBadGprBase + i;
   }
   for (size_t i = 0; i < kNumberOfDRegisters; ++i) {
diff --git a/runtime/arch/arm64/context_arm64.h b/runtime/arch/arm64/context_arm64.h
index 1f69869..d9a433b 100644
--- a/runtime/arch/arm64/context_arm64.h
+++ b/runtime/arch/arm64/context_arm64.h
@@ -34,7 +34,7 @@
 
   void Reset() OVERRIDE;
 
-  void FillCalleeSaves(const StackVisitor& fr) OVERRIDE;
+  void FillCalleeSaves(const StackVisitor& fr) OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void SetSP(uintptr_t new_sp) OVERRIDE {
     bool success = SetGPR(SP, new_sp);
@@ -47,12 +47,12 @@
   }
 
   uintptr_t* GetGPRAddress(uint32_t reg) OVERRIDE {
-    DCHECK_LT(reg, static_cast<uint32_t>(kNumberOfCoreRegisters));
+    DCHECK_LT(reg, static_cast<uint32_t>(kNumberOfXRegisters));
     return gprs_[reg];
   }
 
   bool GetGPR(uint32_t reg, uintptr_t* val) OVERRIDE {
-    DCHECK_LT(reg, static_cast<uint32_t>(kNumberOfCoreRegisters));
+    DCHECK_LT(reg, static_cast<uint32_t>(kNumberOfXRegisters));
     if (gprs_[reg] == nullptr) {
       return false;
     } else {
@@ -82,7 +82,7 @@
 
  private:
   // Pointers to register locations, initialized to NULL or the specific registers below.
-  uintptr_t* gprs_[kNumberOfCoreRegisters];
+  uintptr_t* gprs_[kNumberOfXRegisters];
   uint64_t * fprs_[kNumberOfDRegisters];
   // Hold values for sp and pc if they are not located within a stack frame.
   uintptr_t sp_, pc_;
diff --git a/runtime/arch/arm64/entrypoints_init_arm64.cc b/runtime/arch/arm64/entrypoints_init_arm64.cc
index 70e93b3..871e1d1 100644
--- a/runtime/arch/arm64/entrypoints_init_arm64.cc
+++ b/runtime/arch/arm64/entrypoints_init_arm64.cc
@@ -20,17 +20,11 @@
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "entrypoints/entrypoint_utils.h"
 #include "entrypoints/math_entrypoints.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
+#include "interpreter/interpreter.h"
 
 namespace art {
 
-// Interpreter entrypoints.
-extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh,
-                                                 const DexFile::CodeItem* code_item,
-                                                 ShadowFrame* shadow_frame, JValue* result);
-extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh,
-                                           const DexFile::CodeItem* code_item,
-                                           ShadowFrame* shadow_frame, JValue* result);
-
 // Portable entrypoints.
 extern "C" void art_portable_resolution_trampoline(mirror::ArtMethod*);
 extern "C" void art_portable_to_interpreter_bridge(mirror::ArtMethod*);
diff --git a/runtime/arch/arm64/portable_entrypoints_arm64.S b/runtime/arch/arm64/portable_entrypoints_arm64.S
index 41711b5..9e2c030 100644
--- a/runtime/arch/arm64/portable_entrypoints_arm64.S
+++ b/runtime/arch/arm64/portable_entrypoints_arm64.S
@@ -25,4 +25,6 @@
 
 UNIMPLEMENTED art_portable_resolution_trampoline
 
-UNIMPLEMENTED_NO_HIDE art_portable_to_interpreter_bridge
+UNIMPLEMENTED art_portable_to_interpreter_bridge
+
+UNIMPLEMENTED art_portable_imt_conflict_trampoline
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 52a2a88..147d434 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -79,13 +79,16 @@
 
     // Loads appropriate callee-save-method
     str xIP0, [sp]    // Store ArtMethod* Runtime::callee_save_methods_[kRefsAndArgs]
+    // Place sp in Thread::Current()->top_quick_frame.
+    mov xIP0, sp
+    str xIP0, [xSELF, # THREAD_TOP_QUICK_FRAME_OFFSET]
 .endm
 
     /*
      * Macro that sets up the callee save frame to conform with
      * Runtime::CreateCalleeSaveMethod(kRefsOnly).
      */
-.macro SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+.macro SETUP_REFS_ONLY_CALLEE_SAVE_FRAME
     adrp xIP0, :got:_ZN3art7Runtime9instance_E
     ldr xIP0, [xIP0, #:got_lo12:_ZN3art7Runtime9instance_E]
 
@@ -133,11 +136,14 @@
     mov xETR, xSELF
 
     // Loads appropriate callee-save-method
-    str xIP0, [sp]    // Store ArtMethod* Runtime::callee_save_methods_[kRefsAndArgs]
+    str xIP0, [sp]    // Store ArtMethod* Runtime::callee_save_methods_[kRefsOnly]
+    // Place sp in Thread::Current()->top_quick_frame.
+    mov xIP0, sp
+    str xIP0, [xSELF, # THREAD_TOP_QUICK_FRAME_OFFSET]
 .endm
 
 // TODO: Probably no need to restore registers preserved by aapcs64.
-.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+.macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     // Restore xSELF.
     mov xSELF, xETR
 
@@ -170,7 +176,7 @@
     .cfi_adjust_cfa_offset -96
 .endm
 
-.macro POP_REF_ONLY_CALLEE_SAVE_FRAME
+.macro POP_REFS_ONLY_CALLEE_SAVE_FRAME
     // Restore xSELF as it might be scratched.
     mov xSELF, xETR
     // ETR
@@ -181,13 +187,13 @@
     .cfi_adjust_cfa_offset -96
 .endm
 
-.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+.macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     ret
 .endm
 
 
-.macro SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
+.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
     sub sp, sp, #224
     .cfi_adjust_cfa_offset 224
 
@@ -251,7 +257,7 @@
      *
      * TODO This is probably too conservative - saving FP & LR.
      */
-.macro SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
+.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     adrp xIP0, :got:_ZN3art7Runtime9instance_E
     ldr xIP0, [xIP0, #:got_lo12:_ZN3art7Runtime9instance_E]
 
@@ -260,15 +266,26 @@
 
     // xIP0 = (ArtMethod*) Runtime.instance_.callee_save_methods[kRefAndArgs]  .
     THIS_LOAD_REQUIRES_READ_BARRIER
-    ldr xIP0, [xIP0, RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET ]
+    ldr xIP0, [xIP0, RUNTIME_REFS_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET ]
 
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
 
     str xIP0, [sp]    // Store ArtMethod* Runtime::callee_save_methods_[kRefsAndArgs]
+    // Place sp in Thread::Current()->top_quick_frame.
+    mov xIP0, sp
+    str xIP0, [xSELF, # THREAD_TOP_QUICK_FRAME_OFFSET]
+.endm
+
+.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_X0
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
+    str x0, [sp, #0]  // Store ArtMethod* to bottom of stack.
+    // Place sp in Thread::Current()->top_quick_frame.
+    mov xIP0, sp
+    str xIP0, [xSELF, # THREAD_TOP_QUICK_FRAME_OFFSET]
 .endm
 
 // TODO: Probably no need to restore registers preserved by aapcs64.
-.macro RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+.macro RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     // Restore xSELF.
     mov xSELF, xETR
 
@@ -340,10 +357,9 @@
 .macro DELIVER_PENDING_EXCEPTION
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
     mov x0, xSELF
-    mov x1, sp
 
     // Point of no return.
-    b artDeliverPendingExceptionFromCode  // artDeliverPendingExceptionFromCode(Thread*, SP)
+    b artDeliverPendingExceptionFromCode  // artDeliverPendingExceptionFromCode(Thread*)
     brk 0  // Unreached
 .endm
 
@@ -376,8 +392,7 @@
 ENTRY \c_name
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
     mov x0, xSELF                     // pass Thread::Current
-    mov x1, sp                        // pass SP
-    b   \cxx_name                     // \cxx_name(Thread*, SP)
+    b   \cxx_name                     // \cxx_name(Thread*)
 END \c_name
 .endm
 
@@ -386,8 +401,7 @@
 ENTRY \c_name
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context.
     mov x1, xSELF                     // pass Thread::Current.
-    mov x2, sp                        // pass SP.
-    b   \cxx_name                     // \cxx_name(arg, Thread*, SP).
+    b   \cxx_name                     // \cxx_name(arg, Thread*).
     brk 0
 END \c_name
 .endm
@@ -397,8 +411,7 @@
 ENTRY \c_name
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
     mov x2, xSELF                     // pass Thread::Current
-    mov x3, sp                        // pass SP
-    b   \cxx_name                     // \cxx_name(arg1, arg2, Thread*, SP)
+    b   \cxx_name                     // \cxx_name(arg1, arg2, Thread*)
     brk 0
 END \c_name
 .endm
@@ -458,7 +471,7 @@
 .macro INVOKE_TRAMPOLINE c_name, cxx_name
     .extern \cxx_name
 ENTRY \c_name
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME  // save callee saves in case allocation triggers GC
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME  // save callee saves in case allocation triggers GC
     // Helper signature is always
     // (method_idx, *this_object, *caller_method, *self, sp)
 
@@ -467,7 +480,7 @@
     mov    x4, sp
     bl     \cxx_name                      // (method_idx, this, caller, Thread*, SP)
     mov    xIP0, x1                       // save Method*->code_
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     cbz    x0, 1f                         // did we find the target? if not go to exception delivery
     br     xIP0                           // tail call to target
 1:
@@ -551,7 +564,7 @@
 .macro INVOKE_STUB_CALL_AND_RETURN
 
     // load method-> METHOD_QUICK_CODE_OFFSET
-    ldr x9, [x0 , #METHOD_QUICK_CODE_OFFSET]
+    ldr x9, [x0 , #MIRROR_ART_METHOD_QUICK_CODE_OFFSET]
     // Branch to method.
     blr x9
 
@@ -945,7 +958,7 @@
     .extern artLockObjectFromCode
 ENTRY art_quick_lock_object
     cbz    w0, .Lslow_lock
-    add    x4, x0, #LOCK_WORD_OFFSET  // exclusive load/store had no immediate anymore
+    add    x4, x0, #MIRROR_OBJECT_LOCK_WORD_OFFSET  // exclusive load/store has no immediate anymore
 .Lretry_lock:
     ldr    w2, [xSELF, #THREAD_ID_OFFSET] // TODO: Can the thread ID really change during the loop?
     ldxr   w1, [x4]
@@ -966,14 +979,13 @@
     add    w2, w1, #65536             // increment count in lock word placing in w2 for storing
     lsr    w1, w2, 30                 // if either of the top two bits are set, we overflowed.
     cbnz   w1, .Lslow_lock            // if we overflow the count go slow path
-    str    w2, [x0, #LOCK_WORD_OFFSET]// no need for stxr as we hold the lock
+    str    w2, [x0, #MIRROR_OBJECT_LOCK_WORD_OFFSET]  // no need for stxr as we hold the lock
     ret
 .Lslow_lock:
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case we block
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case we block
     mov    x1, xSELF                  // pass Thread::Current
-    mov    x2, sp                     // pass SP
-    bl     artLockObjectFromCode      // (Object* obj, Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    bl     artLockObjectFromCode      // (Object* obj, Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     RETURN_IF_W0_IS_ZERO_OR_DELIVER
 END art_quick_lock_object
 
@@ -986,7 +998,7 @@
     .extern artUnlockObjectFromCode
 ENTRY art_quick_unlock_object
     cbz    x0, .Lslow_unlock
-    ldr    w1, [x0, #LOCK_WORD_OFFSET]
+    ldr    w1, [x0, #MIRROR_OBJECT_LOCK_WORD_OFFSET]
     lsr    w2, w1, 30
     cbnz   w2, .Lslow_unlock          // if either of the top two bits are set, go slow path
     ldr    w2, [xSELF, #THREAD_ID_OFFSET]
@@ -997,18 +1009,17 @@
     bpl    .Lrecursive_thin_unlock
     // transition to unlocked, w3 holds 0
     dmb    ish                        // full (LoadStore|StoreStore) memory barrier
-    str    w3, [x0, #LOCK_WORD_OFFSET]
+    str    w3, [x0, #MIRROR_OBJECT_LOCK_WORD_OFFSET]
     ret
 .Lrecursive_thin_unlock:
     sub    w1, w1, #65536
-    str    w1, [x0, #LOCK_WORD_OFFSET]
+    str    w1, [x0, #MIRROR_OBJECT_LOCK_WORD_OFFSET]
     ret
 .Lslow_unlock:
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case exception allocation triggers GC
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case exception allocation triggers GC
     mov    x1, xSELF                  // pass Thread::Current
-    mov    x2, sp                     // pass SP
-    bl     artUnlockObjectFromCode    // (Object* obj, Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    bl     artUnlockObjectFromCode    // (Object* obj, Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     RETURN_IF_W0_IS_ZERO_OR_DELIVER
 END art_quick_unlock_object
 
@@ -1058,8 +1069,7 @@
 
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
     mov x2, xSELF                     // pass Thread::Current
-    mov x3, sp                        // pass SP
-    b artThrowClassCastException      // (Class*, Class*, Thread*, SP)
+    b artThrowClassCastException      // (Class*, Class*, Thread*)
     brk 0                             // We should not return here...
 END art_quick_check_cast
 
@@ -1082,7 +1092,7 @@
 END art_quick_aput_obj_with_null_and_bound_check
 
 ENTRY art_quick_aput_obj_with_bound_check
-    ldr w3, [x0, #ARRAY_LENGTH_OFFSET]
+    ldr w3, [x0, #MIRROR_ARRAY_LENGTH_OFFSET]
     cmp w3, w1
     bhi art_quick_aput_obj
     mov x0, x1
@@ -1092,16 +1102,16 @@
 
 ENTRY art_quick_aput_obj
     cbz x2, .Ldo_aput_null
-    ldr w3, [x0, #CLASS_OFFSET]                          // Heap reference = 32b
+    ldr w3, [x0, #MIRROR_OBJECT_CLASS_OFFSET]            // Heap reference = 32b
                                                          // This also zero-extends to x3
-    ldr w4, [x2, #CLASS_OFFSET]                          // Heap reference = 32b
+    ldr w4, [x2, #MIRROR_OBJECT_CLASS_OFFSET]            // Heap reference = 32b
                                                          // This also zero-extends to x4
-    ldr w3, [x3, #CLASS_COMPONENT_TYPE_OFFSET]           // Heap reference = 32b
+    ldr w3, [x3, #MIRROR_CLASS_COMPONENT_TYPE_OFFSET]    // Heap reference = 32b
                                                          // This also zero-extends to x3
     cmp w3, w4  // value's type == array's component type - trivial assignability
     bne .Lcheck_assignability
 .Ldo_aput:
-    add x3, x0, #OBJECT_ARRAY_DATA_OFFSET
+    add x3, x0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET
                                                          // "Compress" = do nothing
     str w2, [x3, x1, lsl #2]                             // Heap reference = 32b
     ldr x3, [xSELF, #THREAD_CARD_TABLE_OFFSET]
@@ -1109,7 +1119,7 @@
     strb w3, [x3, x0]
     ret
 .Ldo_aput_null:
-    add x3, x0, #OBJECT_ARRAY_DATA_OFFSET
+    add x3, x0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET
                                                          // "Compress" = do nothing
     str w2, [x3, x1, lsl #2]                             // Heap reference = 32b
     ret
@@ -1146,7 +1156,7 @@
     add sp, sp, #48
     .cfi_adjust_cfa_offset -48
 
-    add x3, x0, #OBJECT_ARRAY_DATA_OFFSET
+    add x3, x0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET
                                                           // "Compress" = do nothing
     str w2, [x3, x1, lsl #2]                              // Heap reference = 32b
     ldr x3, [xSELF, #THREAD_CARD_TABLE_OFFSET]
@@ -1168,8 +1178,7 @@
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
     mov x1, x2                    // Pass value.
     mov x2, xSELF                 // Pass Thread::Current.
-    mov x3, sp                    // Pass SP.
-    b artThrowArrayStoreException // (Object*, Object*, Thread*, SP).
+    b artThrowArrayStoreException // (Object*, Object*, Thread*).
     brk 0                         // Unreached.
 END art_quick_aput_obj
 
@@ -1177,11 +1186,10 @@
 .macro TWO_ARG_DOWNCALL name, entrypoint, return
     .extern \entrypoint
 ENTRY \name
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case of GC
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case of GC
     mov    x2, xSELF                  // pass Thread::Current
-    mov    x3, sp                     // pass SP
-    bl     \entrypoint                // (uint32_t type_idx, Method* method, Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    bl     \entrypoint                // (uint32_t type_idx, Method* method, Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     \return
     DELIVER_PENDING_EXCEPTION
 END \name
@@ -1191,11 +1199,10 @@
 .macro THREE_ARG_DOWNCALL name, entrypoint, return
     .extern \entrypoint
 ENTRY \name
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case of GC
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case of GC
     mov    x3, xSELF                  // pass Thread::Current
-    mov    x4, sp                     // pass SP
     bl     \entrypoint
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     \return
     DELIVER_PENDING_EXCEPTION
 END \name
@@ -1205,12 +1212,11 @@
 .macro ONE_ARG_REF_DOWNCALL name, entrypoint, return
     .extern \entrypoint
 ENTRY \name
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case of GC
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case of GC
     ldr    w1, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] // Load referrer
     mov    x2, xSELF                  // pass Thread::Current
-    mov    x3, sp                     // pass SP
     bl     \entrypoint                // (uint32_t type_idx, Method* method, Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     \return
 END \name
 .endm
@@ -1218,12 +1224,11 @@
 .macro TWO_ARG_REF_DOWNCALL name, entrypoint, return
     .extern \entrypoint
 ENTRY \name
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case of GC
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case of GC
     ldr    w2, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] // Load referrer
     mov    x3, xSELF                  // pass Thread::Current
-    mov    x4, sp                     // pass SP
     bl     \entrypoint
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     \return
 END \name
 .endm
@@ -1231,12 +1236,11 @@
 .macro THREE_ARG_REF_DOWNCALL name, entrypoint, return
     .extern \entrypoint
 ENTRY \name
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case of GC
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case of GC
     ldr    w3, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] // Load referrer
     mov    x4, xSELF                  // pass Thread::Current
-    mov    x5, sp                     // pass SP
     bl     \entrypoint
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     \return
 END \name
 .endm
@@ -1281,20 +1285,19 @@
 THREE_ARG_REF_DOWNCALL art_quick_set8_instance, artSet8InstanceFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER
 THREE_ARG_REF_DOWNCALL art_quick_set16_instance, artSet16InstanceFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER
 THREE_ARG_REF_DOWNCALL art_quick_set32_instance, artSet32InstanceFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER
-THREE_ARG_DOWNCALL art_quick_set64_instance, artSet64InstanceFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER
+THREE_ARG_REF_DOWNCALL art_quick_set64_instance, artSet64InstanceFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER
 THREE_ARG_REF_DOWNCALL art_quick_set_obj_instance, artSetObjInstanceFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER
 
 // This is separated out as the argument order is different.
     .extern artSet64StaticFromCode
 ENTRY art_quick_set64_static
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case of GC
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case of GC
     mov    x3, x1                     // Store value
     ldr    w1, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] // Load referrer
     mov    x2, x3                     // Put value param
     mov    x3, xSELF                  // pass Thread::Current
-    mov    x4, sp                     // pass SP
     bl     artSet64StaticFromCode
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     RETURN_IF_W0_IS_ZERO_OR_DELIVER
 END art_quick_set64_static
 
@@ -1320,18 +1323,16 @@
     ret                                       // return if flags == 0
 .Lneed_suspend:
     mov    x0, xSELF
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME          // save callee saves for stack crawl
-    mov    x1, sp
-    bl     artTestSuspendFromCode             // (Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME          // save callee saves for stack crawl
+    bl     artTestSuspendFromCode             // (Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
 END art_quick_test_suspend
 
 ENTRY art_quick_implicit_suspend
     mov    x0, xSELF
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME          // save callee saves for stack crawl
-    mov    x1, sp
-    bl     artTestSuspendFromCode             // (Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME          // save callee saves for stack crawl
+    bl     artTestSuspendFromCode             // (Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
 END art_quick_implicit_suspend
 
      /*
@@ -1341,19 +1342,18 @@
      */
      .extern artQuickProxyInvokeHandler
 ENTRY art_quick_proxy_invoke_handler
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    str     x0, [sp, #0]                // place proxy method at bottom of frame
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_X0
     mov     x2, xSELF                   // pass Thread::Current
     mov     x3, sp                      // pass SP
     bl      artQuickProxyInvokeHandler  // (Method* proxy method, receiver, Thread*, SP)
     // Use xETR as xSELF might be scratched by native function above.
     ldr     x2, [xETR, THREAD_EXCEPTION_OFFSET]
     cbnz    x2, .Lexception_in_proxy    // success if no exception is pending
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME // Restore frame
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME // Restore frame
     fmov    d0, x0                      // Store result in d0 in case it was float or double
     ret                                 // return on success
 .Lexception_in_proxy:
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     DELIVER_PENDING_EXCEPTION
 END art_quick_proxy_invoke_handler
 
@@ -1363,24 +1363,24 @@
      */
 ENTRY art_quick_imt_conflict_trampoline
     ldr    w0, [sp, #0]                                // load caller Method*
-    ldr    w0, [x0, #METHOD_DEX_CACHE_METHODS_OFFSET]  // load dex_cache_resolved_methods
-    add    x0, x0, #OBJECT_ARRAY_DATA_OFFSET           // get starting address of data
+    ldr    w0, [x0, #MIRROR_ART_METHOD_DEX_CACHE_METHODS_OFFSET]  // load dex_cache_resolved_methods
+    add    x0, x0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET    // get starting address of data
     ldr    w0, [x0, xIP1, lsl 2]                       // load the target method
     b art_quick_invoke_interface_trampoline
 END art_quick_imt_conflict_trampoline
 
 ENTRY art_quick_resolution_trampoline
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     mov x2, xSELF
     mov x3, sp
     bl artQuickResolutionTrampoline  // (called, receiver, Thread*, SP)
     cbz x0, 1f
     mov xIP0, x0            // Remember returned code pointer in xIP0.
     ldr w0, [sp, #0]        // artQuickResolutionTrampoline puts called method in *SP.
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     br xIP0
 1:
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     DELIVER_PENDING_EXCEPTION
 END art_quick_resolution_trampoline
 
@@ -1438,9 +1438,8 @@
     /*
      * Called to do a generic JNI down-call
      */
-ENTRY_NO_HIDE art_quick_generic_jni_trampoline
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
-    str x0, [sp, #0]  // Store native ArtMethod* to bottom of stack.
+ENTRY art_quick_generic_jni_trampoline
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_X0
 
     // Save SP , so we can have static CFI info.
     mov x28, sp
@@ -1513,7 +1512,7 @@
     cbnz x1, .Lexception_in_native
 
     // Tear down the callee-save frame.
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
 
     // store into fpr, for when it's a fpr return...
     fmov d0, x0
@@ -1523,7 +1522,7 @@
     mov sp, x28
     .cfi_def_cfa_register sp
 .Lexception_in_native:
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     DELIVER_PENDING_EXCEPTION
 
 END art_quick_generic_jni_trampoline
@@ -1534,8 +1533,8 @@
  * x0 = method being called/to bridge to.
  * x1..x7, d0..d7 = arguments to that method.
  */
-ENTRY_NO_HIDE art_quick_to_interpreter_bridge
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME   // Set up frame and save arguments.
+ENTRY art_quick_to_interpreter_bridge
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME   // Set up frame and save arguments.
 
     //  x0 will contain mirror::ArtMethod* method.
     mov x1, xSELF                          // How to get Thread::Current() ???
@@ -1545,7 +1544,7 @@
     //                                      mirror::ArtMethod** sp)
     bl   artQuickToInterpreterBridge
 
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME  // TODO: no need to restore arguments in this case.
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME  // TODO: no need to restore arguments in this case.
 
     fmov d0, x0
 
@@ -1558,19 +1557,18 @@
 //
     .extern artInstrumentationMethodEntryFromCode
 ENTRY art_quick_instrumentation_entry
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
 
     mov   x20, x0             // Preserve method reference in a callee-save.
 
     mov   x2, xSELF
-    mov   x3, sp
-    mov   x4, xLR
-    bl    artInstrumentationMethodEntryFromCode  // (Method*, Object*, Thread*, SP, LR)
+    mov   x3, xLR
+    bl    artInstrumentationMethodEntryFromCode  // (Method*, Object*, Thread*, LR)
 
     mov   xIP0, x0            // x0 = result of call.
     mov   x0, x20             // Reload method reference.
 
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME  // Note: will restore xSELF
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME  // Note: will restore xSELF
     adr   xLR, art_quick_instrumentation_exit
     br    xIP0                // Tail-call method with lr set to art_quick_instrumentation_exit.
 END art_quick_instrumentation_entry
@@ -1579,7 +1577,7 @@
 ENTRY art_quick_instrumentation_exit
     mov   xLR, #0             // Clobber LR for later checks.
 
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME
 
     // We need to save x0 and d0. We could use a callee-save from SETUP_REF_ONLY, but then
     // we would need to fully restore it. As there are a lot of callee-save registers, it seems
@@ -1602,7 +1600,7 @@
     ldr   x0, [sp], 16        // Restore integer result, and drop stack area.
     .cfi_adjust_cfa_offset 16
 
-    POP_REF_ONLY_CALLEE_SAVE_FRAME
+    POP_REFS_ONLY_CALLEE_SAVE_FRAME
 
     br    xIP0                // Tail-call out.
 END art_quick_instrumentation_exit
@@ -1615,8 +1613,7 @@
 ENTRY art_quick_deoptimize
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
     mov    x0, xSELF          // Pass thread.
-    mov    x1, sp             // Pass SP.
-    bl     artDeoptimize      // artDeoptimize(Thread*, SP)
+    bl     artDeoptimize      // artDeoptimize(Thread*)
     brk 0
 END art_quick_deoptimize
 
@@ -1631,9 +1628,9 @@
      *    w2:   Starting offset in string data
      */
 ENTRY art_quick_indexof
-    ldr   w3, [x0, #STRING_COUNT_OFFSET]
-    ldr   w4, [x0, #STRING_OFFSET_OFFSET]
-    ldr   w0, [x0, #STRING_VALUE_OFFSET] // x0 ?
+    ldr   w3, [x0, #MIRROR_STRING_COUNT_OFFSET]
+    ldr   w4, [x0, #MIRROR_STRING_OFFSET_OFFSET]
+    ldr   w0, [x0, #MIRROR_STRING_VALUE_OFFSET] // x0 ?
 
     /* Clamp start to [0..count] */
     cmp   w2, #0
@@ -1642,7 +1639,7 @@
     csel  w2, w3, w2, gt
 
     /* Build a pointer to the start of the string data */
-    add   x0, x0, #STRING_DATA_OFFSET
+    add   x0, x0, #MIRROR_CHAR_ARRAY_DATA_OFFSET
     add   x0, x0, x4, lsl #1
 
     /* Save a copy to compute result */
@@ -1736,12 +1733,12 @@
     ret
 1:                        // Different string objects.
 
-    ldr    w6, [x2, #STRING_OFFSET_OFFSET]
-    ldr    w5, [x1, #STRING_OFFSET_OFFSET]
-    ldr    w4, [x2, #STRING_COUNT_OFFSET]
-    ldr    w3, [x1, #STRING_COUNT_OFFSET]
-    ldr    w2, [x2, #STRING_VALUE_OFFSET]
-    ldr    w1, [x1, #STRING_VALUE_OFFSET]
+    ldr    w6, [x2, #MIRROR_STRING_OFFSET_OFFSET]
+    ldr    w5, [x1, #MIRROR_STRING_OFFSET_OFFSET]
+    ldr    w4, [x2, #MIRROR_STRING_COUNT_OFFSET]
+    ldr    w3, [x1, #MIRROR_STRING_COUNT_OFFSET]
+    ldr    w2, [x2, #MIRROR_STRING_VALUE_OFFSET]
+    ldr    w1, [x1, #MIRROR_STRING_VALUE_OFFSET]
 
     /*
      * Now:           CharArray*    Offset   Count
@@ -1761,8 +1758,8 @@
     add x1, x1, w5, sxtw #1
 
     // Add offset in CharArray to array.
-    add x2, x2, #STRING_DATA_OFFSET
-    add x1, x1, #STRING_DATA_OFFSET
+    add x2, x2, #MIRROR_CHAR_ARRAY_DATA_OFFSET
+    add x1, x1, #MIRROR_CHAR_ARRAY_DATA_OFFSET
 
     // TODO: Tune this value.
     // Check for long string, do memcmp16 for them.
diff --git a/runtime/arch/arm64/registers_arm64.cc b/runtime/arch/arm64/registers_arm64.cc
index 87901e3..ea4383a 100644
--- a/runtime/arch/arm64/registers_arm64.cc
+++ b/runtime/arch/arm64/registers_arm64.cc
@@ -32,11 +32,11 @@
   "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8", "w9",
   "w10", "w11", "w12", "w13", "w14", "w15", "w16", "w17", "w18", "w19",
   "w20", "w21", "w22", "w23", "w24", "w25", "w26", "w27", "w28", "w29",
-  "w30", "wsp", "wxr"
+  "w30", "wsp", "wzr"
 };
 
-std::ostream& operator<<(std::ostream& os, const Register& rhs) {
-  if (rhs >= X0 && rhs <= XZR) {
+std::ostream& operator<<(std::ostream& os, const XRegister& rhs) {
+  if (rhs >= X0 && rhs < kNumberOfXRegisters) {
     os << kRegisterNames[rhs];
   } else {
     os << "XRegister[" << static_cast<int>(rhs) << "]";
@@ -45,7 +45,7 @@
 }
 
 std::ostream& operator<<(std::ostream& os, const WRegister& rhs) {
-  if (rhs >= W0 && rhs <= WZR) {
+  if (rhs >= W0 && rhs < kNumberOfWRegisters) {
     os << kWRegisterNames[rhs];
   } else {
     os << "WRegister[" << static_cast<int>(rhs) << "]";
diff --git a/runtime/arch/arm64/registers_arm64.h b/runtime/arch/arm64/registers_arm64.h
index 9ccab70..51ae184 100644
--- a/runtime/arch/arm64/registers_arm64.h
+++ b/runtime/arch/arm64/registers_arm64.h
@@ -23,7 +23,7 @@
 namespace arm64 {
 
 // Values for GP XRegisters - 64bit registers.
-enum Register {
+enum XRegister {
   X0  =  0,
   X1  =  1,
   X2  =  2,
@@ -55,20 +55,20 @@
   X28 = 28,
   X29 = 29,
   X30 = 30,
-  X31 = 31,
-  TR  = 18,     // ART Thread Register - Managed Runtime (Caller Saved Reg)
-  ETR = 21,     // ART Thread Register - External Calls  (Callee Saved Reg)
-  IP0 = 16,     // Used as scratch by VIXL.
-  IP1 = 17,     // Used as scratch by ART JNI Assembler.
-  FP  = 29,
-  LR  = 30,
-  SP  = 31,     // SP is X31 and overlaps with XRZ but we encode it as a
-                // special register, due to the different instruction semantics.
-  XZR = 32,
-  kNumberOfCoreRegisters = 33,
+  SP  = 31,      // SP and XZR are encoded in instructions using the register
+  XZR = 32,      // code `31`, the context deciding which is used. We use a
+                 // different enum value to distinguish between the two.
+  kNumberOfXRegisters = 33,
+  // Aliases.
+  TR  = X18,     // ART Thread Register - Managed Runtime (Caller Saved Reg)
+  ETR = X21,     // ART Thread Register - External Calls  (Callee Saved Reg)
+  IP0 = X16,     // Used as scratch by VIXL.
+  IP1 = X17,     // Used as scratch by ART JNI Assembler.
+  FP  = X29,
+  LR  = X30,
   kNoRegister = -1,
 };
-std::ostream& operator<<(std::ostream& os, const Register& rhs);
+std::ostream& operator<<(std::ostream& os, const XRegister& rhs);
 
 // Values for GP WRegisters - 32bit registers.
 enum WRegister {
@@ -103,9 +103,9 @@
   W28 = 28,
   W29 = 29,
   W30 = 30,
-  W31 = 31,
-  WZR = 31,
-  kNumberOfWRegisters = 32,
+  WSP = 31,
+  WZR = 32,
+  kNumberOfWRegisters = 33,
   kNoWRegister = -1,
 };
 std::ostream& operator<<(std::ostream& os, const WRegister& rhs);
diff --git a/runtime/arch/mips/asm_support_mips.S b/runtime/arch/mips/asm_support_mips.S
index d8ec9cd..0d18f1a 100644
--- a/runtime/arch/mips/asm_support_mips.S
+++ b/runtime/arch/mips/asm_support_mips.S
@@ -26,15 +26,31 @@
 // Register holding Thread::Current().
 #define rSELF $s1
 
-
-    /* Cache alignment for function entry */
+     // Declare a function called name, sets up $gp.
 .macro ENTRY name
     .type \name, %function
     .global \name
+    // Cache alignment for function entry.
     .balign 16
 \name:
     .cfi_startproc
-     /* Ensure we get a sane starting CFA. */
+     // Ensure we get a sane starting CFA.
+    .cfi_def_cfa $sp,0
+    // Load $gp. We expect that ".set noreorder" is in effect.
+    .cpload $t9
+    // Declare a local convenience label to be branched to when $gp is already set up.
+.L\name\()_gp_set:
+.endm
+
+     // Declare a function called name, doesn't set up $gp.
+.macro ENTRY_NO_GP name
+    .type \name, %function
+    .global \name
+    // Cache alignment for function entry.
+    .balign 16
+\name:
+    .cfi_startproc
+     // Ensure we get a sane starting CFA.
     .cfi_def_cfa $sp,0
 .endm
 
@@ -43,11 +59,6 @@
     .size \name, .-\name
 .endm
 
-    /* Generates $gp for function calls */
-.macro GENERATE_GLOBAL_POINTER
-    .cpload $t9
-.endm
-
 .macro UNIMPLEMENTED name
     ENTRY \name
     break
diff --git a/runtime/arch/mips/asm_support_mips.h b/runtime/arch/mips/asm_support_mips.h
index 6add93b..5bece18 100644
--- a/runtime/arch/mips/asm_support_mips.h
+++ b/runtime/arch/mips/asm_support_mips.h
@@ -19,18 +19,8 @@
 
 #include "asm_support.h"
 
-// Offset of field Thread::tls32_.state_and_flags verified in InitCpu
-#define THREAD_FLAGS_OFFSET 0
-// Offset of field Thread::tlsPtr_.card_table verified in InitCpu
-#define THREAD_CARD_TABLE_OFFSET 120
-// Offset of field Thread::tlsPtr_.exception verified in InitCpu
-#define THREAD_EXCEPTION_OFFSET 124
-
 #define FRAME_SIZE_SAVE_ALL_CALLEE_SAVE 64
 #define FRAME_SIZE_REFS_ONLY_CALLEE_SAVE 64
 #define FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE 64
 
-// Expected size of a heap reference
-#define HEAP_REFERENCE_SIZE 4
-
 #endif  // ART_RUNTIME_ARCH_MIPS_ASM_SUPPORT_MIPS_H_
diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc
index 25e911d..db0f71f 100644
--- a/runtime/arch/mips/entrypoints_init_mips.cc
+++ b/runtime/arch/mips/entrypoints_init_mips.cc
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "atomic.h"
 #include "entrypoints/interpreter/interpreter_entrypoints.h"
 #include "entrypoints/jni/jni_entrypoints.h"
 #include "entrypoints/portable/portable_entrypoints.h"
@@ -21,18 +22,11 @@
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "entrypoints/entrypoint_utils.h"
 #include "entrypoints/math_entrypoints.h"
-#include "atomic.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
+#include "interpreter/interpreter.h"
 
 namespace art {
 
-// Interpreter entrypoints.
-extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh,
-                                                 const DexFile::CodeItem* code_item,
-                                                 ShadowFrame* shadow_frame, JValue* result);
-extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh,
-                                           const DexFile::CodeItem* code_item,
-                                           ShadowFrame* shadow_frame, JValue* result);
-
 // Portable entrypoints.
 extern "C" void art_portable_resolution_trampoline(mirror::ArtMethod*);
 extern "C" void art_portable_to_interpreter_bridge(mirror::ArtMethod*);
diff --git a/runtime/arch/mips/jni_entrypoints_mips.S b/runtime/arch/mips/jni_entrypoints_mips.S
index e5f4a79..9a79467 100644
--- a/runtime/arch/mips/jni_entrypoints_mips.S
+++ b/runtime/arch/mips/jni_entrypoints_mips.S
@@ -24,7 +24,6 @@
      */
     .extern artFindNativeMethod
 ENTRY art_jni_dlsym_lookup_stub
-    GENERATE_GLOBAL_POINTER
     addiu $sp, $sp, -32          # leave room for $a0, $a1, $a2, $a3, and $ra
     .cfi_adjust_cfa_offset 32
     sw     $ra, 16($sp)
diff --git a/runtime/arch/mips/memcmp16_mips.S b/runtime/arch/mips/memcmp16_mips.S
index 0196edc..aef81af 100644
--- a/runtime/arch/mips/memcmp16_mips.S
+++ b/runtime/arch/mips/memcmp16_mips.S
@@ -20,7 +20,7 @@
 #include "asm_support_mips.S"
 
 // u4 __memcmp16(const u2*, const u2*, size_t);
-ENTRY __memcmp16
+ENTRY_NO_GP __memcmp16
   li  $t0,0
   li  $t1,0
   beqz  $a2,done   /* 0 length string */
diff --git a/runtime/arch/mips/portable_entrypoints_mips.S b/runtime/arch/mips/portable_entrypoints_mips.S
index 7545ce0..d7e7a8e 100644
--- a/runtime/arch/mips/portable_entrypoints_mips.S
+++ b/runtime/arch/mips/portable_entrypoints_mips.S
@@ -21,7 +21,6 @@
 
     .extern artPortableProxyInvokeHandler
 ENTRY art_portable_proxy_invoke_handler
-    GENERATE_GLOBAL_POINTER
     # Fake callee save ref and args frame set up, note portable doesn't use callee save frames.
     # TODO: just save the registers that are needed in artPortableProxyInvokeHandler.
     addiu  $sp, $sp, -64
@@ -72,7 +71,6 @@
      *   [sp + 20] = result type char
      */
 ENTRY art_portable_invoke_stub
-    GENERATE_GLOBAL_POINTER
     sw    $a0, 0($sp)           # save out a0
     addiu $sp, $sp, -16         # spill s0, s1, fp, ra
     .cfi_adjust_cfa_offset 16
@@ -87,7 +85,7 @@
     move  $fp, $sp              # save sp in fp
     .cfi_def_cfa_register 30
     move  $s1, $a3              # move managed thread pointer into s1
-    addiu $s0, $zero, SUSPEND_CHECK_INTERVAL  # reset s0 to suspend check interval
+    addiu $s0, $zero, SUSPEND_CHECK_INTERVAL  # reset s0 to suspend check interval. TODO: unused?
     addiu $t0, $a2, 16          # create space for method pointer in frame
     srl   $t0, $t0, 3           # shift the frame size right 3
     sll   $t0, $t0, 3           # shift the frame size left 3 to align to 16 bytes
@@ -100,7 +98,7 @@
     lw    $a1, 4($sp)           # copy arg value for a1
     lw    $a2, 8($sp)           # copy arg value for a2
     lw    $a3, 12($sp)          # copy arg value for a3
-    lw    $t9, METHOD_PORTABLE_CODE_OFFSET($a0)  # get pointer to the code
+    lw    $t9, MIRROR_ART_METHOD_PORTABLE_CODE_OFFSET($a0)  # get pointer to the code
     jalr  $t9                   # call the method
     sw    $zero, 0($sp)         # store NULL for method* at bottom of frame
     move  $sp, $fp              # restore the stack
@@ -131,3 +129,4 @@
 
 UNIMPLEMENTED art_portable_resolution_trampoline
 UNIMPLEMENTED art_portable_to_interpreter_bridge
+UNIMPLEMENTED art_portable_imt_conflict_trampoline
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index 609c65a..905b867 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -29,7 +29,8 @@
     /*
      * Macro that sets up the callee save frame to conform with
      * Runtime::CreateCalleeSaveMethod(kSaveAll)
-     * callee-save: $s0-$s8 + $gp + $ra, 11 total + 1 word padding + 4 open words for args
+     * Callee-save: $s0-$s8 + $gp + $ra, 11 total + 1 word padding + 4 open words for args
+     * Clobbers $t0 and $gp
      */
 .macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
     addiu  $sp, $sp, -64
@@ -63,6 +64,12 @@
     sw     $s0, 20($sp)
     .cfi_rel_offset 16, 20
     # 1 word for alignment, 4 open words for args $a0-$a3, bottom will hold Method*
+
+    ld $t0, _ZN3art7Runtime9instance_E
+    THIS_LOAD_REQUIRES_READ_BARRIER
+    ld $t0, RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET($t0)
+    sw $t0, 0($sp)                                # Place Method* at bottom of stack.
+    sw $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)  # Place sp in Thread::Current()->top_quick_frame.
 .endm
 
     /*
@@ -71,7 +78,7 @@
      * Does not include rSUSPEND or rSELF
      * callee-save: $s2-$s8 + $gp + $ra, 9 total + 3 words padding + 4 open words for args
      */
-.macro SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+.macro SETUP_REFS_ONLY_CALLEE_SAVE_FRAME
     addiu  $sp, $sp, -64
     .cfi_adjust_cfa_offset 64
 
@@ -99,9 +106,15 @@
     sw     $s2, 28($sp)
     .cfi_rel_offset 18, 28
     # 3 words for alignment and extra args, 4 open words for args $a0-$a3, bottom will hold Method*
+
+    ld $t0, _ZN3art7Runtime9instance_E
+    THIS_LOAD_REQUIRES_READ_BARRIER
+    ld $t0, RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET($t0)
+    sw $t0, 0($sp)                                # Place Method* at bottom of stack.
+    sw $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)  # Place sp in Thread::Current()->top_quick_frame.
 .endm
 
-.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+.macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     lw     $ra, 60($sp)
     .cfi_restore 31
     lw     $s8, 56($sp)
@@ -124,7 +137,7 @@
     .cfi_adjust_cfa_offset -64
 .endm
 
-.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
+.macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
     lw     $ra, 60($sp)
     .cfi_restore 31
     lw     $s8, 56($sp)
@@ -153,7 +166,7 @@
      * Runtime::CreateCalleeSaveMethod(kRefsAndArgs). Restoration assumes non-moving GC.
      * callee-save: $a1-$a3, $s2-$s8 + $gp + $ra, 12 total + 3 words padding + method*
      */
-.macro SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
+.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     addiu  $sp, $sp, -64
     .cfi_adjust_cfa_offset 64
 
@@ -187,9 +200,15 @@
     sw     $a1, 4($sp)
     .cfi_rel_offset 5, 4
     # bottom will hold Method*
+
+    ld $t0, _ZN3art7Runtime9instance_E
+    THIS_LOAD_REQUIRES_READ_BARRIER
+    ld $t0, RUNTIME_REFS_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET($t0)
+    sw $t0, 0($sp)                                # Place Method* at bottom of stack.
+    sw $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)  # Place sp in Thread::Current()->top_quick_frame.
 .endm
 
-.macro RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+.macro RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     lw     $ra, 60($sp)
     .cfi_restore 31
     lw     $s8, 56($sp)
@@ -224,15 +243,14 @@
      */
 .macro DELIVER_PENDING_EXCEPTION
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME     # save callee saves for throw
-    move    $a0, rSELF                   # pass Thread::Current
     la      $t9, artDeliverPendingExceptionFromCode
-    jr      $t9                          # artDeliverPendingExceptionFromCode(Thread*, $sp)
-    move    $a1, $sp                     # pass $sp
+    jr      $t9                          # artDeliverPendingExceptionFromCode(Thread*)
+    move    $a0, rSELF                   # pass Thread::Current
 .endm
 
 .macro RETURN_IF_NO_EXCEPTION
     lw     $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     bnez   $t0, 1f                       # success if no exception is pending
     nop
     jr     $ra
@@ -242,7 +260,7 @@
 .endm
 
 .macro RETURN_IF_ZERO
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     bnez   $v0, 1f                       # success?
     nop
     jr     $ra                           # return on success
@@ -252,7 +270,7 @@
 .endm
 
 .macro RETURN_IF_RESULT_IS_NON_ZERO
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     beqz   $v0, 1f                       # success?
     nop
     jr     $ra                           # return on success
@@ -342,12 +360,10 @@
      * the bottom of the thread. On entry r0 holds Throwable*
      */
 ENTRY art_quick_deliver_exception
-    GENERATE_GLOBAL_POINTER
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
-    move $a1, rSELF                 # pass Thread::Current
     la   $t9, artDeliverExceptionFromCode
-    jr   $t9                        # artDeliverExceptionFromCode(Throwable*, Thread*, $sp)
-    move $a2, $sp                   # pass $sp
+    jr   $t9                        # artDeliverExceptionFromCode(Throwable*, Thread*)
+    move $a1, rSELF                 # pass Thread::Current
 END art_quick_deliver_exception
 
     /*
@@ -355,13 +371,10 @@
      */
     .extern artThrowNullPointerExceptionFromCode
 ENTRY art_quick_throw_null_pointer_exception
-    GENERATE_GLOBAL_POINTER
-.Lart_quick_throw_null_pointer_exception_gp_set:
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
-    move $a0, rSELF                 # pass Thread::Current
     la   $t9, artThrowNullPointerExceptionFromCode
-    jr   $t9                        # artThrowNullPointerExceptionFromCode(Thread*, $sp)
-    move $a1, $sp                   # pass $sp
+    jr   $t9                        # artThrowNullPointerExceptionFromCode(Thread*)
+    move $a0, rSELF                 # pass Thread::Current
 END art_quick_throw_null_pointer_exception
 
     /*
@@ -369,12 +382,10 @@
      */
     .extern artThrowDivZeroFromCode
 ENTRY art_quick_throw_div_zero
-    GENERATE_GLOBAL_POINTER
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
-    move $a0, rSELF                 # pass Thread::Current
     la   $t9, artThrowDivZeroFromCode
-    jr   $t9                        # artThrowDivZeroFromCode(Thread*, $sp)
-    move $a1, $sp                   # pass $sp
+    jr   $t9                        # artThrowDivZeroFromCode(Thread*)
+    move $a0, rSELF                 # pass Thread::Current
 END art_quick_throw_div_zero
 
     /*
@@ -382,13 +393,10 @@
      */
     .extern artThrowArrayBoundsFromCode
 ENTRY art_quick_throw_array_bounds
-    GENERATE_GLOBAL_POINTER
-.Lart_quick_throw_array_bounds_gp_set:
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
-    move $a2, rSELF                 # pass Thread::Current
     la   $t9, artThrowArrayBoundsFromCode
-    jr   $t9                        # artThrowArrayBoundsFromCode(index, limit, Thread*, $sp)
-    move $a3, $sp                   # pass $sp
+    jr   $t9                        # artThrowArrayBoundsFromCode(index, limit, Thread*)
+    move $a2, rSELF                 # pass Thread::Current
 END art_quick_throw_array_bounds
 
     /*
@@ -396,12 +404,10 @@
      */
     .extern artThrowStackOverflowFromCode
 ENTRY art_quick_throw_stack_overflow
-    GENERATE_GLOBAL_POINTER
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
-    move $a0, rSELF                 # pass Thread::Current
     la   $t9, artThrowStackOverflowFromCode
-    jr   $t9                        # artThrowStackOverflowFromCode(Thread*, $sp)
-    move $a1, $sp                   # pass $sp
+    jr   $t9                        # artThrowStackOverflowFromCode(Thread*)
+    move $a0, rSELF                 # pass Thread::Current
 END art_quick_throw_stack_overflow
 
     /*
@@ -409,12 +415,10 @@
      */
     .extern artThrowNoSuchMethodFromCode
 ENTRY art_quick_throw_no_such_method
-    GENERATE_GLOBAL_POINTER
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
-    move $a1, rSELF                 # pass Thread::Current
     la   $t9, artThrowNoSuchMethodFromCode
-    jr   $t9                        # artThrowNoSuchMethodFromCode(method_idx, Thread*, $sp)
-    move $a2, $sp                   # pass $sp
+    jr   $t9                        # artThrowNoSuchMethodFromCode(method_idx, Thread*)
+    move $a1, rSELF                 # pass Thread::Current
 END art_quick_throw_no_such_method
 
     /*
@@ -436,9 +440,8 @@
 .macro INVOKE_TRAMPOLINE c_name, cxx_name
     .extern \cxx_name
 ENTRY \c_name
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME  # save callee saves in case allocation triggers GC
-    lw    $a2, 64($sp)                    # pass caller Method*
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME  # save callee saves in case allocation triggers GC
+    lw    $a2, FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE($sp)                    # pass caller Method*
     move  $t0, $sp                        # save $sp
     addiu $sp, $sp, -32                   # make space for extra args
     .cfi_adjust_cfa_offset 32
@@ -450,7 +453,7 @@
     .cfi_adjust_cfa_offset -32
     move  $a0, $v0                        # save target Method*
     move  $t9, $v1                        # save $v0->code_
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     beqz  $v0, 1f
     nop
     jr    $t9
@@ -479,7 +482,6 @@
      *   [sp + 20] = shorty
      */
 ENTRY art_quick_invoke_stub
-    GENERATE_GLOBAL_POINTER
     sw    $a0, 0($sp)           # save out a0
     addiu $sp, $sp, -16         # spill s0, s1, fp, ra
     .cfi_adjust_cfa_offset 16
@@ -507,7 +509,7 @@
     lw    $a1, 4($sp)           # copy arg value for a1
     lw    $a2, 8($sp)           # copy arg value for a2
     lw    $a3, 12($sp)          # copy arg value for a3
-    lw    $t9, METHOD_QUICK_CODE_OFFSET($a0)  # get pointer to the code
+    lw    $t9, MIRROR_ART_METHOD_QUICK_CODE_OFFSET($a0)  # get pointer to the code
     jalr  $t9                   # call the method
     sw    $zero, 0($sp)         # store NULL for method* at bottom of frame
     move  $sp, $fp              # restore the stack
@@ -543,12 +545,10 @@
      */
     .extern artHandleFillArrayDataFromCode
 ENTRY art_quick_handle_fill_data
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  # save callee saves in case exception allocation triggers GC
-    lw     $a2, 64($sp)                   # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  # save callee saves in case exception allocation triggers GC
+    lw     $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)                   # pass referrer's Method*
+    jal    artHandleFillArrayDataFromCode # (payload offset, Array*, method, Thread*)
     move   $a3, rSELF                     # pass Thread::Current
-    jal    artHandleFillArrayDataFromCode # (payload offset, Array*, method, Thread*, $sp)
-    sw     $sp, 16($sp)                   # pass $sp
     RETURN_IF_ZERO
 END art_quick_handle_fill_data
 
@@ -557,13 +557,11 @@
      */
     .extern artLockObjectFromCode
 ENTRY art_quick_lock_object
-    GENERATE_GLOBAL_POINTER
     beqz    $a0, .Lart_quick_throw_null_pointer_exception_gp_set
     nop
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME      # save callee saves in case we block
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME      # save callee saves in case we block
+    jal     artLockObjectFromCode         # (Object* obj, Thread*)
     move    $a1, rSELF                    # pass Thread::Current
-    jal     artLockObjectFromCode         # (Object* obj, Thread*, $sp)
-    move    $a2, $sp                      # pass $sp
     RETURN_IF_ZERO
 END art_quick_lock_object
 
@@ -572,13 +570,11 @@
      */
     .extern artUnlockObjectFromCode
 ENTRY art_quick_unlock_object
-    GENERATE_GLOBAL_POINTER
     beqz    $a0, .Lart_quick_throw_null_pointer_exception_gp_set
     nop
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  # save callee saves in case exception allocation triggers GC
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  # save callee saves in case exception allocation triggers GC
+    jal     artUnlockObjectFromCode   # (Object* obj, Thread*)
     move    $a1, rSELF                # pass Thread::Current
-    jal     artUnlockObjectFromCode   # (Object* obj, Thread*, $sp)
-    move    $a2, $sp                  # pass $sp
     RETURN_IF_ZERO
 END art_quick_unlock_object
 
@@ -587,7 +583,6 @@
      */
     .extern artThrowClassCastException
 ENTRY art_quick_check_cast
-    GENERATE_GLOBAL_POINTER
     addiu  $sp, $sp, -16
     .cfi_adjust_cfa_offset 16
     sw     $ra, 12($sp)
@@ -609,10 +604,9 @@
     addiu  $sp, $sp, 16
     .cfi_adjust_cfa_offset -16
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
-    move $a2, rSELF                 # pass Thread::Current
     la   $t9, artThrowClassCastException
-    jr   $t9                        # artThrowClassCastException (Class*, Class*, Thread*, SP)
-    move $a3, $sp                   # pass $sp
+    jr   $t9                        # artThrowClassCastException (Class*, Class*, Thread*)
+    move $a2, rSELF                 # pass Thread::Current
 END art_quick_check_cast
 
     /*
@@ -621,7 +615,6 @@
      * a0 = array, a1 = index, a2 = value
      */
 ENTRY art_quick_aput_obj_with_null_and_bound_check
-    GENERATE_GLOBAL_POINTER
     bnez    $a0, .Lart_quick_aput_obj_with_bound_check_gp_set
     nop
     b .Lart_quick_throw_null_pointer_exception_gp_set
@@ -629,9 +622,7 @@
 END art_quick_aput_obj_with_null_and_bound_check
 
 ENTRY art_quick_aput_obj_with_bound_check
-    GENERATE_GLOBAL_POINTER
-.Lart_quick_aput_obj_with_bound_check_gp_set:
-    lw $t0, ARRAY_LENGTH_OFFSET($a0)
+    lw $t0, MIRROR_ARRAY_LENGTH_OFFSET($a0)
     sltu $t1, $a1, $t0
     bnez $t1, .Lart_quick_aput_obj_gp_set
     nop
@@ -641,19 +632,17 @@
 END art_quick_aput_obj_with_bound_check
 
 ENTRY art_quick_aput_obj
-    GENERATE_GLOBAL_POINTER
-.Lart_quick_aput_obj_gp_set:
     beqz $a2, .Ldo_aput_null
     nop
-    lw $t0, CLASS_OFFSET($a0)
-    lw $t1, CLASS_OFFSET($a2)
-    lw $t0, CLASS_COMPONENT_TYPE_OFFSET($t0)
+    lw $t0, MIRROR_OBJECT_CLASS_OFFSET($a0)
+    lw $t1, MIRROR_OBJECT_CLASS_OFFSET($a2)
+    lw $t0, MIRROR_CLASS_COMPONENT_TYPE_OFFSET($t0)
     bne $t1, $t0, .Lcheck_assignability  # value's type == array's component type - trivial assignability
     nop
 .Ldo_aput:
     sll $a1, $a1, 2
     add $t0, $a0, $a1
-    sw  $a2, OBJECT_ARRAY_DATA_OFFSET($t0)
+    sw  $a2, MIRROR_OBJECT_ARRAY_DATA_OFFSET($t0)
     lw  $t0, THREAD_CARD_TABLE_OFFSET(rSELF)
     srl $t1, $a0, 7
     add $t1, $t1, $t0
@@ -663,7 +652,7 @@
 .Ldo_aput_null:
     sll $a1, $a1, 2
     add $t0, $a0, $a1
-    sw  $a2, OBJECT_ARRAY_DATA_OFFSET($t0)
+    sw  $a2, MIRROR_OBJECT_ARRAY_DATA_OFFSET($t0)
     jr  $ra
     nop
 .Lcheck_assignability:
@@ -690,10 +679,9 @@
     nop
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
     move $a1, $a2
-    move $a2, rSELF                 # pass Thread::Current
     la   $t9, artThrowArrayStoreException
-    jr   $t9                        # artThrowArrayStoreException(Class*, Class*, Thread*, SP)
-    move $a3, $sp                   # pass $sp
+    jr   $t9                        # artThrowArrayStoreException(Class*, Class*, Thread*)
+    move $a2, rSELF                 # pass Thread::Current
 END art_quick_aput_obj
 
     /*
@@ -703,12 +691,10 @@
      */
     .extern artInitializeStaticStorageFromCode
 ENTRY art_quick_initialize_static_storage
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME            # save callee saves in case of GC
-    move    $a2, rSELF                          # pass Thread::Current
-    # artInitializeStaticStorageFromCode(uint32_t type_idx, Method* referrer, Thread*, $sp)
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME            # save callee saves in case of GC
+    # artInitializeStaticStorageFromCode(uint32_t type_idx, Method* referrer, Thread*)
     jal     artInitializeStaticStorageFromCode
-    move    $a3, $sp                            # pass $sp
+    move    $a2, rSELF                          # pass Thread::Current
     RETURN_IF_RESULT_IS_NON_ZERO
 END art_quick_initialize_static_storage
 
@@ -717,12 +703,10 @@
      */
     .extern artInitializeTypeFromCode
 ENTRY art_quick_initialize_type
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME           # save callee saves in case of GC
-    move    $a2, rSELF                         # pass Thread::Current
-    # artInitializeTypeFromCode(uint32_t type_idx, Method* referrer, Thread*, $sp)
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME           # save callee saves in case of GC
+    # artInitializeTypeFromCode(uint32_t type_idx, Method* referrer, Thread*)
     jal     artInitializeTypeFromCode
-    move    $a3, $sp                           # pass $sp
+    move    $a2, rSELF                         # pass Thread::Current
     RETURN_IF_RESULT_IS_NON_ZERO
 END art_quick_initialize_type
 
@@ -732,12 +716,10 @@
      */
     .extern artInitializeTypeAndVerifyAccessFromCode
 ENTRY art_quick_initialize_type_and_verify_access
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME           # save callee saves in case of GC
-    move    $a2, rSELF                         # pass Thread::Current
-    # artInitializeTypeFromCode(uint32_t type_idx, Method* referrer, Thread*, $sp)
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME           # save callee saves in case of GC
+    # artInitializeTypeFromCode(uint32_t type_idx, Method* referrer, Thread*)
     jal     artInitializeTypeAndVerifyAccessFromCode
-    move    $a3, $sp                           # pass $sp
+    move    $a2, rSELF                         # pass Thread::Current
     RETURN_IF_RESULT_IS_NON_ZERO
 END art_quick_initialize_type_and_verify_access
     /*
@@ -745,12 +727,10 @@
      */
     .extern artGetBooleanStaticFromCode
 ENTRY art_quick_get_boolean_static
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a1, 64($sp)                  # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a1, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
+    jal    artGetBooleanStaticFromCode   # (uint32_t field_idx, const Method* referrer, Thread*)
     move   $a2, rSELF                    # pass Thread::Current
-    jal    artGetBooleanStaticFromCode   # (uint32_t field_idx, const Method* referrer, Thread*, $sp)
-    move   $a3, $sp                      # pass $sp
     RETURN_IF_NO_EXCEPTION
 END art_quick_get_boolean_static
     /*
@@ -758,12 +738,10 @@
      */
     .extern artGetByteStaticFromCode
 ENTRY art_quick_get_byte_static
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a1, 64($sp)                  # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a1, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
+    jal    artGetByteStaticFromCode      # (uint32_t field_idx, const Method* referrer, Thread*)
     move   $a2, rSELF                    # pass Thread::Current
-    jal    artGetByteStaticFromCode      # (uint32_t field_idx, const Method* referrer, Thread*, $sp)
-    move   $a3, $sp                      # pass $sp
     RETURN_IF_NO_EXCEPTION
 END art_quick_get_byte_static
 
@@ -772,12 +750,10 @@
      */
     .extern artGetCharStaticFromCode
 ENTRY art_quick_get_char_static
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a1, 64($sp)                  # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a1, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
+    jal    artGetCharStaticFromCode      # (uint32_t field_idx, const Method* referrer, Thread*)
     move   $a2, rSELF                    # pass Thread::Current
-    jal    artGetCharStaticFromCode      # (uint32_t field_idx, const Method* referrer, Thread*, $sp)
-    move   $a3, $sp                      # pass $sp
     RETURN_IF_NO_EXCEPTION
 END art_quick_get_char_static
     /*
@@ -785,12 +761,10 @@
      */
     .extern artGetShortStaticFromCode
 ENTRY art_quick_get_short_static
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a1, 64($sp)                  # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a1, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
+    jal    artGetShortStaticFromCode     # (uint32_t field_idx, const Method* referrer, Thread*)
     move   $a2, rSELF                    # pass Thread::Current
-    jal    artGetShortStaticFromCode     # (uint32_t field_idx, const Method* referrer, Thread*, $sp)
-    move   $a3, $sp                      # pass $sp
     RETURN_IF_NO_EXCEPTION
 END art_quick_get_short_static
 
@@ -799,12 +773,10 @@
      */
     .extern artGet32StaticFromCode
 ENTRY art_quick_get32_static
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a1, 64($sp)                  # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a1, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
+    jal    artGet32StaticFromCode        # (uint32_t field_idx, const Method* referrer, Thread*)
     move   $a2, rSELF                    # pass Thread::Current
-    jal    artGet32StaticFromCode        # (uint32_t field_idx, const Method* referrer, Thread*, $sp)
-    move   $a3, $sp                      # pass $sp
     RETURN_IF_NO_EXCEPTION
 END art_quick_get32_static
 
@@ -813,12 +785,10 @@
      */
     .extern artGet64StaticFromCode
 ENTRY art_quick_get64_static
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a1, 64($sp)                  # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a1, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
+    jal    artGet64StaticFromCode        # (uint32_t field_idx, const Method* referrer, Thread*)
     move   $a2, rSELF                    # pass Thread::Current
-    jal    artGet64StaticFromCode        # (uint32_t field_idx, const Method* referrer, Thread*, $sp)
-    move   $a3, $sp                      # pass $sp
     RETURN_IF_NO_EXCEPTION
 END art_quick_get64_static
 
@@ -827,12 +797,10 @@
      */
     .extern artGetObjStaticFromCode
 ENTRY art_quick_get_obj_static
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a1, 64($sp)                  # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a1, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
+    jal    artGetObjStaticFromCode       # (uint32_t field_idx, const Method* referrer, Thread*)
     move   $a2, rSELF                    # pass Thread::Current
-    jal    artGetObjStaticFromCode       # (uint32_t field_idx, const Method* referrer, Thread*, $sp)
-    move   $a3, $sp                      # pass $sp
     RETURN_IF_NO_EXCEPTION
 END art_quick_get_obj_static
 
@@ -841,12 +809,10 @@
      */
     .extern artGetBooleanInstanceFromCode
 ENTRY art_quick_get_boolean_instance
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a2, 64($sp)                  # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
+    jal    artGetBooleanInstanceFromCode # (field_idx, Object*, referrer, Thread*)
     move   $a3, rSELF                    # pass Thread::Current
-    jal    artGetBooleanInstanceFromCode # (field_idx, Object*, referrer, Thread*, $sp)
-    sw     $sp, 16($sp)                  # pass $sp
     RETURN_IF_NO_EXCEPTION
 END art_quick_get_boolean_instance
     /*
@@ -854,12 +820,10 @@
      */
     .extern artGetByteInstanceFromCode
 ENTRY art_quick_get_byte_instance
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a2, 64($sp)                  # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
+    jal    artGetByteInstanceFromCode    # (field_idx, Object*, referrer, Thread*)
     move   $a3, rSELF                    # pass Thread::Current
-    jal    artGetByteInstanceFromCode    # (field_idx, Object*, referrer, Thread*, $sp)
-    sw     $sp, 16($sp)                  # pass $sp
     RETURN_IF_NO_EXCEPTION
 END art_quick_get_byte_instance
 
@@ -868,12 +832,10 @@
      */
     .extern artGetCharInstanceFromCode
 ENTRY art_quick_get_char_instance
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a2, 64($sp)                  # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
+    jal    artGetCharInstanceFromCode    # (field_idx, Object*, referrer, Thread*)
     move   $a3, rSELF                    # pass Thread::Current
-    jal    artGetCharInstanceFromCode    # (field_idx, Object*, referrer, Thread*, $sp)
-    sw     $sp, 16($sp)                  # pass $sp
     RETURN_IF_NO_EXCEPTION
 END art_quick_get_char_instance
     /*
@@ -881,12 +843,10 @@
      */
     .extern artGetShortInstanceFromCode
 ENTRY art_quick_get_short_instance
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a2, 64($sp)                  # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
+    jal    artGetShortInstanceFromCode      # (field_idx, Object*, referrer, Thread*)
     move   $a3, rSELF                    # pass Thread::Current
-    jal    artGetShortInstanceFromCode      # (field_idx, Object*, referrer, Thread*, $sp)
-    sw     $sp, 16($sp)                  # pass $sp
     RETURN_IF_NO_EXCEPTION
 END art_quick_get_short_instance
 
@@ -895,9 +855,8 @@
      */
     .extern artGet32InstanceFromCode
 ENTRY art_quick_get32_instance
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a2, 64($sp)                  # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
     move   $a3, rSELF                    # pass Thread::Current
     jal    artGet32InstanceFromCode      # (field_idx, Object*, referrer, Thread*, $sp)
     sw     $sp, 16($sp)                  # pass $sp
@@ -909,9 +868,8 @@
      */
     .extern artGet64InstanceFromCode
 ENTRY art_quick_get64_instance
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a2, 64($sp)                  # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
     move   $a3, rSELF                    # pass Thread::Current
     jal    artGet64InstanceFromCode      # (field_idx, Object*, referrer, Thread*, $sp)
     sw     $sp, 16($sp)                  # pass $sp
@@ -923,12 +881,10 @@
      */
     .extern artGetObjInstanceFromCode
 ENTRY art_quick_get_obj_instance
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a2, 64($sp)                  # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
+    jal    artGetObjInstanceFromCode     # (field_idx, Object*, referrer, Thread*)
     move   $a3, rSELF                    # pass Thread::Current
-    jal    artGetObjInstanceFromCode     # (field_idx, Object*, referrer, Thread*, $sp)
-    sw     $sp, 16($sp)                  # pass $sp
     RETURN_IF_NO_EXCEPTION
 END art_quick_get_obj_instance
 
@@ -937,12 +893,10 @@
      */
     .extern artSet8StaticFromCode
 ENTRY art_quick_set8_static
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a2, 64($sp)                  # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
+    jal    artSet8StaticFromCode         # (field_idx, new_val, referrer, Thread*)
     move   $a3, rSELF                    # pass Thread::Current
-    jal    artSet8StaticFromCode         # (field_idx, new_val, referrer, Thread*, $sp)
-    sw     $sp, 16($sp)                  # pass $sp
     RETURN_IF_ZERO
 END art_quick_set8_static
 
@@ -951,12 +905,10 @@
      */
     .extern artSet16StaticFromCode
 ENTRY art_quick_set16_static
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a2, 64($sp)                  # pass referrer's Method*
-    move   $a3, rSELF                    # pass Thread::Current
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
     jal    artSet16StaticFromCode        # (field_idx, new_val, referrer, Thread*, $sp)
-    sw     $sp, 16($sp)                  # pass $sp
+    move   $a3, rSELF                    # pass Thread::Current
     RETURN_IF_ZERO
 END art_quick_set16_static
 
@@ -965,12 +917,10 @@
      */
     .extern artSet32StaticFromCode
 ENTRY art_quick_set32_static
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a2, 64($sp)                  # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
+    jal    artSet32StaticFromCode        # (field_idx, new_val, referrer, Thread*)
     move   $a3, rSELF                    # pass Thread::Current
-    jal    artSet32StaticFromCode        # (field_idx, new_val, referrer, Thread*, $sp)
-    sw     $sp, 16($sp)                  # pass $sp
     RETURN_IF_ZERO
 END art_quick_set32_static
 
@@ -979,12 +929,10 @@
      */
     .extern artSet64StaticFromCode
 ENTRY art_quick_set64_static
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a1, 64($sp)                  # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a1, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
+    jal    artSet64StaticFromCode        # (field_idx, referrer, new_val, Thread*)
     sw     rSELF, 16($sp)                # pass Thread::Current
-    jal    artSet64StaticFromCode        # (field_idx, referrer, new_val, Thread*, $sp)
-    sw     $sp, 20($sp)                  # pass $sp
     RETURN_IF_ZERO
 END art_quick_set64_static
 
@@ -993,12 +941,10 @@
      */
     .extern artSetObjStaticFromCode
 ENTRY art_quick_set_obj_static
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a2, 64($sp)                  # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
+    jal    artSetObjStaticFromCode       # (field_idx, new_val, referrer, Thread*)
     move   $a3, rSELF                    # pass Thread::Current
-    jal    artSetObjStaticFromCode       # (field_idx, new_val, referrer, Thread*, $sp)
-    sw     $sp, 16($sp)                  # pass $sp
     RETURN_IF_ZERO
 END art_quick_set_obj_static
 
@@ -1007,12 +953,10 @@
      */
     .extern artSet8InstanceFromCode
 ENTRY art_quick_set8_instance
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a3, 64($sp)                  # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a3, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
+    jal    artSet8InstanceFromCode      # (field_idx, Object*, new_val, referrer, Thread*)
     sw     rSELF, 16($sp)                # pass Thread::Current
-    jal    artSet8InstanceFromCode      # (field_idx, Object*, new_val, referrer, Thread*, $sp)
-    sw     $sp, 20($sp)                  # pass $sp
     RETURN_IF_ZERO
 END art_quick_set8_instance
 
@@ -1021,12 +965,10 @@
      */
     .extern artSet16InstanceFromCode
 ENTRY art_quick_set16_instance
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a3, 64($sp)                  # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a3, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
+    jal    artSet16InstanceFromCode      # (field_idx, Object*, new_val, referrer, Thread*)
     sw     rSELF, 16($sp)                # pass Thread::Current
-    jal    artSet16InstanceFromCode      # (field_idx, Object*, new_val, referrer, Thread*, $sp)
-    sw     $sp, 20($sp)                  # pass $sp
     RETURN_IF_ZERO
 END art_quick_set16_instance
 
@@ -1035,12 +977,10 @@
      */
     .extern artSet32InstanceFromCode
 ENTRY art_quick_set32_instance
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a3, 64($sp)                  # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a3, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
+    jal    artSet32InstanceFromCode      # (field_idx, Object*, new_val, referrer, Thread*)
     sw     rSELF, 16($sp)                # pass Thread::Current
-    jal    artSet32InstanceFromCode      # (field_idx, Object*, new_val, referrer, Thread*, $sp)
-    sw     $sp, 20($sp)                  # pass $sp
     RETURN_IF_ZERO
 END art_quick_set32_instance
 
@@ -1049,11 +989,11 @@
      */
     .extern artSet64InstanceFromCode
 ENTRY art_quick_set64_instance
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    sw     rSELF, 16($sp)                # pass Thread::Current
-    jal    artSet64InstanceFromCode      # (field_idx, Object*, new_val, Thread*, $sp)
-    sw     $sp, 20($sp)                  # pass $sp
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $t0, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # load referrer's Method*
+    sw     rSELF, 20($sp)                # pass Thread::Current
+    jal    artSet64InstanceFromCode      # (field_idx, Object*, new_val, referrer, Thread*)
+    sw     $t0, 16($sp)                  # pass referrer's Method*
     RETURN_IF_ZERO
 END art_quick_set64_instance
 
@@ -1062,12 +1002,10 @@
      */
     .extern artSetObjInstanceFromCode
 ENTRY art_quick_set_obj_instance
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
-    lw     $a3, 64($sp)                  # pass referrer's Method*
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case of GC
+    lw     $a3, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
+    jal    artSetObjInstanceFromCode     # (field_idx, Object*, new_val, referrer, Thread*)
     sw     rSELF, 16($sp)                # pass Thread::Current
-    jal    artSetObjInstanceFromCode     # (field_idx, Object*, new_val, referrer, Thread*, $sp)
-    sw     $sp, 20($sp)                  # pass $sp
     RETURN_IF_ZERO
 END art_quick_set_obj_instance
 
@@ -1079,12 +1017,10 @@
      */
     .extern artResolveStringFromCode
 ENTRY art_quick_resolve_string
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  # save callee saves in case of GC
-    move    $a2, rSELF                # pass Thread::Current
-    # artResolveStringFromCode(Method* referrer, uint32_t string_idx, Thread*, $sp)
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  # save callee saves in case of GC
+    # artResolveStringFromCode(Method* referrer, uint32_t string_idx, Thread*)
     jal     artResolveStringFromCode
-    move    $a3, $sp                  # pass $sp
+    move    $a2, rSELF                # pass Thread::Current
     RETURN_IF_RESULT_IS_NON_ZERO
 END art_quick_resolve_string
 
@@ -1093,11 +1029,9 @@
 .macro TWO_ARG_DOWNCALL name, entrypoint, return
     .extern \entrypoint
 ENTRY \name
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  # save callee saves in case of GC
-    move    $a2, rSELF                # pass Thread::Current
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  # save callee saves in case of GC
     jal     \entrypoint
-    move    $a3, $sp                  # pass $sp
+    move    $a2, rSELF                # pass Thread::Current
     \return
 END \name
 .endm
@@ -1105,11 +1039,9 @@
 .macro THREE_ARG_DOWNCALL name, entrypoint, return
     .extern \entrypoint
 ENTRY \name
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  # save callee saves in case of GC
-    move    $a3, rSELF                # pass Thread::Current
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  # save callee saves in case of GC
     jal     \entrypoint
-    sw      $sp, 16($sp)              # pass $sp
+    move    $a3, rSELF                # pass Thread::Current
     \return
 END \name
 .endm
@@ -1122,18 +1054,16 @@
      */
     .extern artTestSuspendFromCode
 ENTRY art_quick_test_suspend
-    GENERATE_GLOBAL_POINTER
     lh     $a0, THREAD_FLAGS_OFFSET(rSELF)
     bnez   $a0, 1f
     addi  rSUSPEND, $zero, SUSPEND_CHECK_INTERVAL   # reset rSUSPEND to SUSPEND_CHECK_INTERVAL
     jr     $ra
     nop
 1:
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME          # save callee saves for stack crawl
+    jal    artTestSuspendFromCode              # (Thread*)
     move   $a0, rSELF
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME          # save callee saves for stack crawl
-    jal    artTestSuspendFromCode             # (Thread*, $sp)
-    move   $a1, $sp
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
 END art_quick_test_suspend
 
     /*
@@ -1142,14 +1072,13 @@
      */
     .extern artQuickProxyInvokeHandler
 ENTRY art_quick_proxy_invoke_handler
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     sw      $a0, 0($sp)            # place proxy method at bottom of frame
     move    $a2, rSELF             # pass Thread::Current
     jal     artQuickProxyInvokeHandler  # (Method* proxy method, receiver, Thread*, SP)
     move    $a3, $sp               # pass $sp
     lw      $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     bnez    $t0, 1f
     mtc1    $v0, $f0               # place return value to FP return value
     jr      $ra
@@ -1162,32 +1091,30 @@
      * Called to resolve an imt conflict. t0 is a hidden argument that holds the target method's
      * dex method index.
      */
-ENTRY art_quick_imt_conflict_trampoline
-    GENERATE_GLOBAL_POINTER
+ENTRY_NO_GP art_quick_imt_conflict_trampoline
     lw      $a0, 0($sp)            # load caller Method*
-    lw      $a0, METHOD_DEX_CACHE_METHODS_OFFSET($a0)  # load dex_cache_resolved_methods
+    lw      $a0, MIRROR_ART_METHOD_DEX_CACHE_METHODS_OFFSET($a0)  # load dex_cache_resolved_methods
     sll     $t0, 2                 # convert target method offset to bytes
     add     $a0, $t0               # get address of target method
-    lw      $a0, OBJECT_ARRAY_DATA_OFFSET($a0)  # load the target method
+    lw      $a0, MIRROR_OBJECT_ARRAY_DATA_OFFSET($a0)  # load the target method
     la      $t9, art_quick_invoke_interface_trampoline
     jr      $t9
 END art_quick_imt_conflict_trampoline
 
     .extern artQuickResolutionTrampoline
 ENTRY art_quick_resolution_trampoline
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     move    $a2, rSELF             # pass Thread::Current
     jal     artQuickResolutionTrampoline  # (Method* called, receiver, Thread*, SP)
     move    $a3, $sp               # pass $sp
     beqz    $v0, 1f
     lw      $a0, 0($sp)            # load resolved method to $a0
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     move    $t9, $v0               # code pointer must be in $t9 to generate the global pointer
     jr      $v0                    # tail call to method
     nop
 1:
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     DELIVER_PENDING_EXCEPTION
 END art_quick_resolution_trampoline
 
@@ -1195,13 +1122,12 @@
 
     .extern artQuickToInterpreterBridge
 ENTRY art_quick_to_interpreter_bridge
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     move    $a1, rSELF             # pass Thread::Current
     jal     artQuickToInterpreterBridge    # (Method* method, Thread*, SP)
     move    $a2, $sp               # pass $sp
     lw      $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     bnez    $t0, 1f
     mtc1    $v0, $f0               # place return value to FP return value
     jr      $ra
@@ -1216,21 +1142,19 @@
     .extern artInstrumentationMethodEntryFromCode
     .extern artInstrumentationMethodExitFromCode
 ENTRY art_quick_instrumentation_entry
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     move     $t0, $sp       # remember bottom of caller's frame
-    addiu    $sp, $sp, -32  # space for args, pad (3 words), arguments (5 words)
+    addiu    $sp, $sp, -32  # space for saved a0, pad (2 words), arguments (4 words)
     .cfi_adjust_cfa_offset 32
     sw       $a0, 28($sp)   # save arg0
-    sw       $ra, 16($sp)   # pass $ra
-    move     $a3, $t0       # pass $sp
-    jal      artInstrumentationMethodEntryFromCode  # (Method*, Object*, Thread*, SP, LR)
+    move     $a3, $ra       # pass $ra
+    jal      artInstrumentationMethodEntryFromCode  # (Method*, Object*, Thread*, LR)
     move     $a2, rSELF     # pass Thread::Current
     move     $t9, $v0       # $t9 holds reference to code
     lw       $a0, 28($sp)   # restore arg0
     addiu    $sp, $sp, 32   # remove args
     .cfi_adjust_cfa_offset -32
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     jalr     $t9            # call method
     nop
 END art_quick_instrumentation_entry
@@ -1239,9 +1163,9 @@
 art_quick_instrumentation_exit:
     .cfi_startproc
     addiu    $t9, $ra, 4    # put current address into $t9 to rebuild $gp
-    GENERATE_GLOBAL_POINTER
+    .cpload  $t9
     move     $ra, $zero     # link register is to here, so clobber with 0 for later checks
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME
     move     $t0, $sp       # remember bottom of caller's frame
     addiu    $sp, $sp, -48  # save return values and set up args
     .cfi_adjust_cfa_offset 48
@@ -1274,14 +1198,11 @@
      * will long jump to the upcall with a special exception of -1.
      */
     .extern artDeoptimize
-    .extern artEnterInterpreterFromDeoptimize
 ENTRY art_quick_deoptimize
-    GENERATE_GLOBAL_POINTER
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
-    move     $a0, rSELF     # pass Thread::current
-    jal      artDeoptimize  # artDeoptimize(Thread*, SP)
+    jal      artDeoptimize  # artDeoptimize(Thread*)
                             # Returns caller method's frame size.
-    move     $a1, $sp       # pass $sp
+    move     $a0, rSELF     # pass Thread::current
 END art_quick_deoptimize
 
     /*
@@ -1294,7 +1215,7 @@
      *   $a1: high word
      *   $a2: shift count
      */
-ENTRY art_quick_shl_long
+ENTRY_NO_GP art_quick_shl_long
     /* shl-long vAA, vBB, vCC */
     sll     $v0, $a0, $a2                    #  rlo<- alo << (shift&31)
     not     $v1, $a2                         #  rhi<- 31-shift  (shift is 5b)
@@ -1318,8 +1239,7 @@
      *   $a1: high word
      *   $a2: shift count
      */
-    .global art_quick_shr_long
-ENTRY art_quick_shr_long
+ENTRY_NO_GP art_quick_shr_long
     sra     $v1, $a1, $a2                    #  rhi<- ahi >> (shift&31)
     srl     $v0, $a0, $a2                    #  rlo<- alo >> (shift&31)
     sra     $a3, $a1, 31                     #  $a3<- sign(ah)
@@ -1344,8 +1264,7 @@
      *   r2: shift count
      */
     /* ushr-long vAA, vBB, vCC */
-    .global art_quick_ushr_long
-ENTRY art_quick_ushr_long
+ENTRY_NO_GP art_quick_ushr_long
     srl     $v1, $a1, $a2                    #  rhi<- ahi >> (shift&31)
     srl     $v0, $a0, $a2                    #  rlo<- alo >> (shift&31)
     not     $a0, $a2                         #  alo<- 31-shift (shift is 5b)
@@ -1358,12 +1277,5 @@
     movn    $v1, $zero, $a2                  #  rhi<- 0 (if shift&0x20)
 END art_quick_ushr_long
 
-ENTRY art_quick_indexof
-    jr $ra
-    nop
-END art_quick_indexof
-
-ENTRY art_quick_string_compareto
-    jr $ra
-    nop
-END art_quick_string_compareto
+UNIMPLEMENTED art_quick_indexof
+UNIMPLEMENTED art_quick_string_compareto
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 6b74a1b..c5a0f6c 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -260,7 +260,7 @@
           "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
           "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
           "memory");  // clobber.
-#elif defined(__x86_64__) && !defined(__APPLE__)
+#elif defined(__x86_64__) && !defined(__APPLE__) && defined(__clang__)
     // Note: Uses the native convention
     // TODO: Set the thread?
     __asm__ __volatile__(
@@ -485,7 +485,7 @@
           "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
           "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
           "memory");  // clobber.
-#elif defined(__x86_64__) && !defined(__APPLE__)
+#elif defined(__x86_64__) && !defined(__APPLE__) && defined(__clang__)
     // Note: Uses the native convention
     // TODO: Set the thread?
     __asm__ __volatile__(
@@ -1148,7 +1148,7 @@
   // For some reason this does not work, as the type_idx is artificial and outside what the
   // resolved types of c_obj allow...
 
-  if (false) {
+  if ((false)) {
     // Use an arbitrary method from c to use as referrer
     size_t result = Invoke3(static_cast<size_t>(c->GetDexTypeIndex()),    // type_idx
                             reinterpret_cast<size_t>(c_obj->GetVirtualMethod(0)),  // arbitrary
@@ -1221,13 +1221,12 @@
   // Use array so we can index into it and use a matrix for expected results
   // Setup: The first half is standard. The second half uses a non-zero offset.
   // TODO: Shared backing arrays.
-  static constexpr size_t kBaseStringCount  = 8;
-  const char* c[kBaseStringCount] = { "", "", "a", "aa", "ab",
+  const char* c[] = { "", "", "a", "aa", "ab",
       "aacaacaacaacaacaac",  // This one's under the default limit to go to __memcmp16.
       "aacaacaacaacaacaacaacaacaacaacaacaac",     // This one's over.
       "aacaacaacaacaacaacaacaacaacaacaacaaca" };  // As is this one. We need a separate one to
                                                   // defeat object-equal optimizations.
-
+  static constexpr size_t kBaseStringCount  = arraysize(c);
   static constexpr size_t kStringCount = 2 * kBaseStringCount;
 
   StackHandleScope<kStringCount> hs(self);
@@ -1337,10 +1336,9 @@
                            mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
-  constexpr size_t num_values = 5;
-  int8_t values[num_values] = { -128, -64, 0, 64, 127 };
+  int8_t values[] = { -128, -64, 0, 64, 127 };
 
-  for (size_t i = 0; i < num_values; ++i) {
+  for (size_t i = 0; i < arraysize(values); ++i) {
     test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
                               static_cast<size_t>(values[i]),
                               0U,
@@ -1367,10 +1365,9 @@
                              Thread* self, mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
-  constexpr size_t num_values = 5;
-  uint8_t values[num_values] = { 0, true, 2, 128, 0xFF };
+  uint8_t values[] = { 0, true, 2, 128, 0xFF };
 
-  for (size_t i = 0; i < num_values; ++i) {
+  for (size_t i = 0; i < arraysize(values); ++i) {
     test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
                               reinterpret_cast<size_t>(obj->Get()),
                               static_cast<size_t>(values[i]),
@@ -1401,10 +1398,9 @@
                              Thread* self, mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
-  constexpr size_t num_values = 5;
-  int8_t values[num_values] = { -128, -64, 0, 64, 127 };
+  int8_t values[] = { -128, -64, 0, 64, 127 };
 
-  for (size_t i = 0; i < num_values; ++i) {
+  for (size_t i = 0; i < arraysize(values); ++i) {
     test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
                               reinterpret_cast<size_t>(obj->Get()),
                               static_cast<size_t>(values[i]),
@@ -1435,10 +1431,9 @@
                            mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
-  constexpr size_t num_values = 6;
-  uint16_t values[num_values] = { 0, 1, 2, 255, 32768, 0xFFFF };
+  uint16_t values[] = { 0, 1, 2, 255, 32768, 0xFFFF };
 
-  for (size_t i = 0; i < num_values; ++i) {
+  for (size_t i = 0; i < arraysize(values); ++i) {
     test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
                               static_cast<size_t>(values[i]),
                               0U,
@@ -1464,10 +1459,9 @@
                            mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
-  constexpr size_t num_values = 6;
-  int16_t values[num_values] = { -0x7FFF, -32768, 0, 255, 32767, 0x7FFE };
+  int16_t values[] = { -0x7FFF, -32768, 0, 255, 32767, 0x7FFE };
 
-  for (size_t i = 0; i < num_values; ++i) {
+  for (size_t i = 0; i < arraysize(values); ++i) {
     test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
                               static_cast<size_t>(values[i]),
                               0U,
@@ -1494,10 +1488,9 @@
                              Thread* self, mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
-  constexpr size_t num_values = 6;
-  uint16_t values[num_values] = { 0, 1, 2, 255, 32768, 0xFFFF };
+  uint16_t values[] = { 0, 1, 2, 255, 32768, 0xFFFF };
 
-  for (size_t i = 0; i < num_values; ++i) {
+  for (size_t i = 0; i < arraysize(values); ++i) {
     test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
                               reinterpret_cast<size_t>(obj->Get()),
                               static_cast<size_t>(values[i]),
@@ -1527,10 +1520,9 @@
                              Thread* self, mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
-  constexpr size_t num_values = 6;
-  int16_t values[num_values] = { -0x7FFF, -32768, 0, 255, 32767, 0x7FFE };
+  int16_t values[] = { -0x7FFF, -32768, 0, 255, 32767, 0x7FFE };
 
-  for (size_t i = 0; i < num_values; ++i) {
+  for (size_t i = 0; i < arraysize(values); ++i) {
     test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
                               reinterpret_cast<size_t>(obj->Get()),
                               static_cast<size_t>(values[i]),
@@ -1561,10 +1553,9 @@
                            mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
-  constexpr size_t num_values = 7;
-  uint32_t values[num_values] = { 0, 1, 2, 255, 32768, 1000000, 0xFFFFFFFF };
+  uint32_t values[] = { 0, 1, 2, 255, 32768, 1000000, 0xFFFFFFFF };
 
-  for (size_t i = 0; i < num_values; ++i) {
+  for (size_t i = 0; i < arraysize(values); ++i) {
     test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
                               static_cast<size_t>(values[i]),
                               0U,
@@ -1592,10 +1583,9 @@
                              Thread* self, mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
-  constexpr size_t num_values = 7;
-  uint32_t values[num_values] = { 0, 1, 2, 255, 32768, 1000000, 0xFFFFFFFF };
+  uint32_t values[] = { 0, 1, 2, 255, 32768, 1000000, 0xFFFFFFFF };
 
-  for (size_t i = 0; i < num_values; ++i) {
+  for (size_t i = 0; i < arraysize(values); ++i) {
     test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
                               reinterpret_cast<size_t>(obj->Get()),
                               static_cast<size_t>(values[i]),
@@ -1716,10 +1706,9 @@
                            mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
 #if (defined(__x86_64__) && !defined(__APPLE__)) || defined(__aarch64__)
-  constexpr size_t num_values = 8;
-  uint64_t values[num_values] = { 0, 1, 2, 255, 32768, 1000000, 0xFFFFFFFF, 0xFFFFFFFFFFFF };
+  uint64_t values[] = { 0, 1, 2, 255, 32768, 1000000, 0xFFFFFFFF, 0xFFFFFFFFFFFF };
 
-  for (size_t i = 0; i < num_values; ++i) {
+  for (size_t i = 0; i < arraysize(values); ++i) {
     test->Invoke3UWithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
                                values[i],
                                StubTest::GetEntrypoint(self, kQuickSet64Static),
@@ -1746,10 +1735,9 @@
                              Thread* self, mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
 #if (defined(__x86_64__) && !defined(__APPLE__)) || defined(__aarch64__)
-  constexpr size_t num_values = 8;
-  uint64_t values[num_values] = { 0, 1, 2, 255, 32768, 1000000, 0xFFFFFFFF, 0xFFFFFFFFFFFF };
+  uint64_t values[] = { 0, 1, 2, 255, 32768, 1000000, 0xFFFFFFFF, 0xFFFFFFFFFFFF };
 
-  for (size_t i = 0; i < num_values; ++i) {
+  for (size_t i = 0; i < arraysize(values); ++i) {
     test->Invoke3WithReferrer(static_cast<size_t>((*f)->GetDexFieldIndex()),
                               reinterpret_cast<size_t>(obj->Get()),
                               static_cast<size_t>(values[i]),
@@ -2109,10 +2097,10 @@
   // Use array so we can index into it and use a matrix for expected results
   // Setup: The first half is standard. The second half uses a non-zero offset.
   // TODO: Shared backing arrays.
-  static constexpr size_t kStringCount = 7;
-  const char* c_str[kStringCount] = { "", "a", "ba", "cba", "dcba", "edcba", "asdfghjkl" };
-  static constexpr size_t kCharCount = 5;
-  const char c_char[kCharCount] = { 'a', 'b', 'c', 'd', 'e' };
+  const char* c_str[] = { "", "a", "ba", "cba", "dcba", "edcba", "asdfghjkl" };
+  static constexpr size_t kStringCount = arraysize(c_str);
+  const char c_char[] = { 'a', 'b', 'c', 'd', 'e' };
+  static constexpr size_t kCharCount = arraysize(c_char);
 
   StackHandleScope<kStringCount> hs(self);
   Handle<mirror::String> s[kStringCount];
diff --git a/runtime/arch/x86/asm_support_x86.S b/runtime/arch/x86/asm_support_x86.S
index efbbfb3..fea16da 100644
--- a/runtime/arch/x86/asm_support_x86.S
+++ b/runtime/arch/x86/asm_support_x86.S
@@ -135,16 +135,6 @@
     CFI_DEF_CFA(esp, 4)
 END_MACRO
 
-MACRO1(DEFINE_FUNCTION_NO_HIDE, c_name)
-    FUNCTION_TYPE(\c_name, 0)
-    .globl VAR(c_name, 0)
-    ALIGN_FUNCTION_ENTRY
-VAR(c_name, 0):
-    CFI_STARTPROC
-    // Ensure we get a sane starting CFA.
-    CFI_DEF_CFA(esp, 4)
-END_MACRO
-
 MACRO1(END_FUNCTION, c_name)
     CFI_ENDPROC
     SIZE(\c_name, 0)
@@ -174,10 +164,14 @@
     SIZE(\name, 0)
 END_MACRO
 
-MACRO0(SETUP_GOT_NOSAVE)
+MACRO1(SETUP_GOT_NOSAVE, got_reg)
 #ifndef __APPLE__
-    call __x86.get_pc_thunk.bx
-    addl $_GLOBAL_OFFSET_TABLE_, %ebx
+    .ifc RAW_VAR(got_reg, 0), ebx
+      call __x86.get_pc_thunk.bx
+      addl $_GLOBAL_OFFSET_TABLE_, %ebx
+    .else
+      .error "Unknown GOT register \got_reg"
+    .endif
 #endif
 END_MACRO
 
diff --git a/runtime/arch/x86/asm_support_x86.h b/runtime/arch/x86/asm_support_x86.h
index c9f5a25..5a88f80 100644
--- a/runtime/arch/x86/asm_support_x86.h
+++ b/runtime/arch/x86/asm_support_x86.h
@@ -19,20 +19,8 @@
 
 #include "asm_support.h"
 
-// Offset of field Thread::self_ verified in InitCpu
-#define THREAD_SELF_OFFSET 156
-// Offset of field Thread::card_table_ verified in InitCpu
-#define THREAD_CARD_TABLE_OFFSET 120
-// Offset of field Thread::exception_ verified in InitCpu
-#define THREAD_EXCEPTION_OFFSET 124
-// Offset of field Thread::thin_lock_thread_id_ verified in InitCpu
-#define THREAD_ID_OFFSET 12
-
 #define FRAME_SIZE_SAVE_ALL_CALLEE_SAVE 32
 #define FRAME_SIZE_REFS_ONLY_CALLEE_SAVE 32
 #define FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE 32
 
-// Expected size of a heap reference
-#define HEAP_REFERENCE_SIZE 4
-
 #endif  // ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_H_
diff --git a/runtime/arch/x86/entrypoints_init_x86.cc b/runtime/arch/x86/entrypoints_init_x86.cc
index 682c502..f2b91cd 100644
--- a/runtime/arch/x86/entrypoints_init_x86.cc
+++ b/runtime/arch/x86/entrypoints_init_x86.cc
@@ -19,18 +19,11 @@
 #include "entrypoints/portable/portable_entrypoints.h"
 #include "entrypoints/quick/quick_alloc_entrypoints.h"
 #include "entrypoints/quick/quick_entrypoints.h"
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
+#include "interpreter/interpreter.h"
 
 namespace art {
 
-// Interpreter entrypoints.
-extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh,
-                                                  const DexFile::CodeItem* code_item,
-                                                  ShadowFrame* shadow_frame, JValue* result);
-extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh,
-                                           const DexFile::CodeItem* code_item,
-                                           ShadowFrame* shadow_frame, JValue* result);
-
 // Portable entrypoints.
 extern "C" void art_portable_resolution_trampoline(mirror::ArtMethod*);
 extern "C" void art_portable_to_interpreter_bridge(mirror::ArtMethod*);
diff --git a/runtime/arch/x86/portable_entrypoints_x86.S b/runtime/arch/x86/portable_entrypoints_x86.S
index f5fe869..a7c4124 100644
--- a/runtime/arch/x86/portable_entrypoints_x86.S
+++ b/runtime/arch/x86/portable_entrypoints_x86.S
@@ -37,7 +37,7 @@
     andl LITERAL(0xFFFFFFF0), %ebx    // align frame size to 16 bytes
     subl LITERAL(12), %ebx        // remove space for return address, ebx, and ebp
     subl %ebx, %esp               // reserve stack space for argument array
-    SETUP_GOT_NOSAVE              // reset ebx to GOT table
+    SETUP_GOT_NOSAVE ebx          // reset ebx to GOT table
     lea  4(%esp), %eax            // use stack pointer + method ptr as dest for memcpy
     pushl 20(%ebp)                // push size of region to memcpy
     pushl 16(%ebp)                // push arg array as source of memcpy
@@ -46,7 +46,7 @@
     addl LITERAL(12), %esp        // pop arguments to memcpy
     mov 12(%ebp), %eax            // move method pointer into eax
     mov %eax, (%esp)              // push method pointer onto stack
-    call *METHOD_PORTABLE_CODE_OFFSET(%eax) // call the method
+    call *MIRROR_ART_METHOD_PORTABLE_CODE_OFFSET(%eax) // call the method
     mov %ebp, %esp                // restore stack pointer
     POP ebx                       // pop ebx
     POP ebp                       // pop ebp
@@ -111,7 +111,7 @@
   ret
 END_FUNCTION art_portable_resolution_trampoline
 
-DEFINE_FUNCTION_NO_HIDE art_portable_to_interpreter_bridge
+DEFINE_FUNCTION art_portable_to_interpreter_bridge
   PUSH ebp                        // Set up frame.
   movl %esp, %ebp
   CFI_DEF_CFA_REGISTER(%ebp)
@@ -127,3 +127,5 @@
   CFI_DEF_CFA(%esp, 4)
   ret
 END_FUNCTION art_portable_to_interpreter_bridge
+
+UNIMPLEMENTED art_portable_imt_conflict_trampoline
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 411d273..69527ce 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -22,12 +22,21 @@
      * Macro that sets up the callee save frame to conform with
      * Runtime::CreateCalleeSaveMethod(kSaveAll)
      */
-MACRO0(SETUP_SAVE_ALL_CALLEE_SAVE_FRAME)
+MACRO2(SETUP_SAVE_ALL_CALLEE_SAVE_FRAME, got_reg, temp_reg)
     PUSH edi  // Save callee saves (ebx is saved/restored by the upcall)
     PUSH esi
     PUSH ebp
-    subl  MACRO_LITERAL(16), %esp  // Grow stack by 4 words, bottom word will hold Method*
-    CFI_ADJUST_CFA_OFFSET(16)
+    subl  MACRO_LITERAL(12), %esp  // Grow stack by 3 words.
+    CFI_ADJUST_CFA_OFFSET(12)
+    SETUP_GOT_NOSAVE RAW_VAR(got_reg, 0)
+    // Load Runtime::instance_ from GOT.
+    movl SYMBOL(_ZN3art7Runtime9instance_E)@GOT(REG_VAR(got_reg, 0)), REG_VAR(temp_reg, 1)
+    movl (REG_VAR(temp_reg, 1)), REG_VAR(temp_reg, 1)
+    // Push save all callee-save method.
+    pushl RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET(REG_VAR(temp_reg, 1))
+    CFI_ADJUST_CFA_OFFSET(4)
+    // Store esp as the top quick frame.
+    movl %esp, %fs:THREAD_TOP_QUICK_FRAME_OFFSET
     // Ugly compile-time check, but we only have the preprocessor.
     // Last +4: implicit return address pushed on stack when caller made call.
 #if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 3*4 + 16 + 4)
@@ -39,12 +48,21 @@
      * Macro that sets up the callee save frame to conform with
      * Runtime::CreateCalleeSaveMethod(kRefsOnly)
      */
-MACRO0(SETUP_REF_ONLY_CALLEE_SAVE_FRAME)
+MACRO2(SETUP_REFS_ONLY_CALLEE_SAVE_FRAME, got_reg, temp_reg)
     PUSH edi  // Save callee saves (ebx is saved/restored by the upcall)
     PUSH esi
     PUSH ebp
-    subl  MACRO_LITERAL(16), %esp  // Grow stack by 4 words, bottom word will hold Method*
-    CFI_ADJUST_CFA_OFFSET(16)
+    subl  MACRO_LITERAL(12), %esp  // Grow stack by 3 words.
+    CFI_ADJUST_CFA_OFFSET(12)
+    SETUP_GOT_NOSAVE VAR(got_reg, 0)
+    // Load Runtime::instance_ from GOT.
+    movl SYMBOL(_ZN3art7Runtime9instance_E)@GOT(REG_VAR(got_reg, 0)), REG_VAR(temp_reg, 1)
+    movl (REG_VAR(temp_reg, 1)), REG_VAR(temp_reg, 1)
+    // Push save all callee-save method.
+    pushl RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET(REG_VAR(temp_reg, 1))
+    CFI_ADJUST_CFA_OFFSET(4)
+    // Store esp as the top quick frame.
+    movl %esp, %fs:THREAD_TOP_QUICK_FRAME_OFFSET
 
     // Ugly compile-time check, but we only have the preprocessor.
     // Last +4: implicit return address pushed on stack when caller made call.
@@ -53,7 +71,7 @@
 #endif
 END_MACRO
 
-MACRO0(RESTORE_REF_ONLY_CALLEE_SAVE_FRAME)
+MACRO0(RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME)
     addl MACRO_LITERAL(16), %esp  // Unwind stack up to saved values
     CFI_ADJUST_CFA_OFFSET(-16)
     POP ebp  // Restore callee saves (ebx is saved/restored by the upcall)
@@ -65,14 +83,22 @@
      * Macro that sets up the callee save frame to conform with
      * Runtime::CreateCalleeSaveMethod(kRefsAndArgs)
      */
-MACRO0(SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME)
+MACRO2(SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME, got_reg, temp_reg)
     PUSH edi  // Save callee saves
     PUSH esi
     PUSH ebp
     PUSH ebx  // Save args
     PUSH edx
     PUSH ecx
-    PUSH eax   // Align stack, eax will be clobbered by Method*
+    SETUP_GOT_NOSAVE VAR(got_reg, 0)
+    // Load Runtime::instance_ from GOT.
+    movl SYMBOL(_ZN3art7Runtime9instance_E)@GOT(REG_VAR(got_reg, 0)), REG_VAR(temp_reg, 1)
+    movl (REG_VAR(temp_reg, 1)), REG_VAR(temp_reg, 1)
+    // Push save all callee-save method.
+    pushl RUNTIME_REFS_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET(REG_VAR(temp_reg, 1))
+    CFI_ADJUST_CFA_OFFSET(4)
+    // Store esp as the stop quick frame.
+    movl %esp, %fs:THREAD_TOP_QUICK_FRAME_OFFSET
 
     // Ugly compile-time check, but we only have the preprocessor.
     // Last +4: implicit return address pushed on stack when caller made call.
@@ -81,7 +107,23 @@
 #endif
 END_MACRO
 
-MACRO0(RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME)
+    /*
+     * Macro that sets up the callee save frame to conform with
+     * Runtime::CreateCalleeSaveMethod(kRefsAndArgs) where the method is passed in EAX.
+     */
+MACRO0(SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_EAX)
+    PUSH edi  // Save callee saves
+    PUSH esi
+    PUSH ebp
+    PUSH ebx  // Save args
+    PUSH edx
+    PUSH ecx
+    PUSH eax  // Store the ArtMethod reference at the bottom of the stack.
+    // Store esp as the stop quick frame.
+    movl %esp, %fs:THREAD_TOP_QUICK_FRAME_OFFSET
+END_MACRO
+
+MACRO0(RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME)
     addl MACRO_LITERAL(4), %esp  // Remove padding
     CFI_ADJUST_CFA_OFFSET(-4)
     POP ecx  // Restore args except eax
@@ -97,59 +139,54 @@
      * exception is Thread::Current()->exception_.
      */
 MACRO0(DELIVER_PENDING_EXCEPTION)
-    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME         // save callee saves for throw
-    mov %esp, %ecx
+    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME ebx, ebx  // save callee saves for throw
     // Outgoing argument set up
-    subl  MACRO_LITERAL(8), %esp             // Alignment padding
-    CFI_ADJUST_CFA_OFFSET(8)
-    PUSH ecx                                 // pass SP
-    pushl %fs:THREAD_SELF_OFFSET             // pass Thread::Current()
+    subl  MACRO_LITERAL(12), %esp              // Alignment padding
+    CFI_ADJUST_CFA_OFFSET(12)
+    pushl %fs:THREAD_SELF_OFFSET               // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
-    call SYMBOL(artDeliverPendingExceptionFromCode)  // artDeliverPendingExceptionFromCode(Thread*, SP)
-    int3                                     // unreached
+    call SYMBOL(artDeliverPendingExceptionFromCode)  // artDeliverPendingExceptionFromCode(Thread*)
+    int3                                       // unreached
 END_MACRO
 
 MACRO2(NO_ARG_RUNTIME_EXCEPTION, c_name, cxx_name)
     DEFINE_FUNCTION RAW_VAR(c_name, 0)
-    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
-    mov %esp, %ecx
+    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  ebx, ebx  // save all registers as basis for long jump context
     // Outgoing argument set up
-    subl  MACRO_LITERAL(8), %esp  // alignment padding
-    CFI_ADJUST_CFA_OFFSET(8)
-    PUSH ecx                      // pass SP
+    subl  MACRO_LITERAL(12), %esp  // alignment padding
+    CFI_ADJUST_CFA_OFFSET(12)
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
-    call VAR(cxx_name, 1)     // cxx_name(Thread*, SP)
+    call VAR(cxx_name, 1)         // cxx_name(Thread*)
     int3                          // unreached
     END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
 
 MACRO2(ONE_ARG_RUNTIME_EXCEPTION, c_name, cxx_name)
     DEFINE_FUNCTION RAW_VAR(c_name, 0)
-    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
+    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME ebx, ebx  // save all registers as basis for long jump context
     mov %esp, %ecx
     // Outgoing argument set up
-    PUSH eax                      // alignment padding
-    PUSH ecx                      // pass SP
+    subl  MACRO_LITERAL(8), %esp  // alignment padding
+    CFI_ADJUST_CFA_OFFSET(8)
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH eax                      // pass arg1
-    call VAR(cxx_name, 1)     // cxx_name(arg1, Thread*, SP)
+    call VAR(cxx_name, 1)         // cxx_name(arg1, Thread*)
     int3                          // unreached
     END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
 
 MACRO2(TWO_ARG_RUNTIME_EXCEPTION, c_name, cxx_name)
     DEFINE_FUNCTION RAW_VAR(c_name, 0)
-    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
-    mov %esp, %edx
+    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME ebx, ebx  // save all registers as basis for long jump context
     // Outgoing argument set up
-    PUSH edx                      // pass SP
+    PUSH eax                      // alignment padding
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH ecx                      // pass arg2
     PUSH eax                      // pass arg1
-    call VAR(cxx_name, 1)     // cxx_name(arg1, arg2, Thread*, SP)
+    call VAR(cxx_name, 1)         // cxx_name(arg1, arg2, Thread*)
     int3                          // unreached
     END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
@@ -204,15 +241,7 @@
      */
 MACRO2(INVOKE_TRAMPOLINE, c_name, cxx_name)
     DEFINE_FUNCTION RAW_VAR(c_name, 0)
-    // Set up the callee save frame to conform with Runtime::CreateCalleeSaveMethod(kRefsAndArgs)
-    // return address
-    PUSH edi
-    PUSH esi
-    PUSH ebp
-    PUSH ebx  // Save args
-    PUSH edx
-    PUSH ecx
-    PUSH eax    // <-- callee save Method* to go here
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME ebx, ebx
     movl %esp, %edx  // remember SP
     // Outgoing argument set up
     subl MACRO_LITERAL(12), %esp  // alignment padding
@@ -224,7 +253,7 @@
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH ecx                      // pass arg2
     PUSH eax                      // pass arg1
-    call VAR(cxx_name, 1)     // cxx_name(arg1, arg2, arg3, Thread*, SP)
+    call VAR(cxx_name, 1)         // cxx_name(arg1, arg2, arg3, Thread*, SP)
     movl %edx, %edi               // save code pointer in EDI
     addl MACRO_LITERAL(36), %esp  // Pop arguments skip eax
     CFI_ADJUST_CFA_OFFSET(-36)
@@ -275,7 +304,7 @@
     andl LITERAL(0xFFFFFFF0), %ebx    // align frame size to 16 bytes
     subl LITERAL(12), %ebx        // remove space for return address, ebx, and ebp
     subl %ebx, %esp               // reserve stack space for argument array
-    SETUP_GOT_NOSAVE              // clobbers ebx (harmless here)
+    SETUP_GOT_NOSAVE ebx          // clobbers ebx (harmless here)
     lea  4(%esp), %eax            // use stack pointer + method ptr as dest for memcpy
     pushl 20(%ebp)                // push size of region to memcpy
     pushl 16(%ebp)                // push arg array as source of memcpy
@@ -287,7 +316,7 @@
     mov 4(%esp), %ecx             // copy arg1 into ecx
     mov 8(%esp), %edx             // copy arg2 into edx
     mov 12(%esp), %ebx            // copy arg3 into ebx
-    call *METHOD_QUICK_CODE_OFFSET(%eax) // call the method
+    call *MIRROR_ART_METHOD_QUICK_CODE_OFFSET(%eax) // call the method
     mov %ebp, %esp                // restore stack pointer
     CFI_DEF_CFA_REGISTER(esp)
     POP ebx                       // pop ebx
@@ -311,120 +340,127 @@
 
 MACRO3(NO_ARG_DOWNCALL, c_name, cxx_name, return_macro)
     DEFINE_FUNCTION RAW_VAR(c_name, 0)
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
-    mov %esp, %edx                // remember SP
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME ebx, ebx  // save ref containing registers for GC
     // Outgoing argument set up
-    subl MACRO_LITERAL(8), %esp   // push padding
-    CFI_ADJUST_CFA_OFFSET(8)
-    PUSH edx                      // pass SP
+    subl MACRO_LITERAL(12), %esp  // push padding
+    CFI_ADJUST_CFA_OFFSET(12)
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
-    call VAR(cxx_name, 1)     // cxx_name(Thread*, SP)
+    call VAR(cxx_name, 1)         // cxx_name(Thread*)
     addl MACRO_LITERAL(16), %esp  // pop arguments
     CFI_ADJUST_CFA_OFFSET(-16)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
     CALL_MACRO(return_macro, 2)   // return or deliver exception
     END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
 
 MACRO3(ONE_ARG_DOWNCALL, c_name, cxx_name, return_macro)
     DEFINE_FUNCTION RAW_VAR(c_name, 0)
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
-    mov %esp, %edx                // remember SP
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  ebx, ebx  // save ref containing registers for GC
     // Outgoing argument set up
-    PUSH eax                      // push padding
-    PUSH edx                      // pass SP
+    subl MACRO_LITERAL(8), %esp   // push padding
+    CFI_ADJUST_CFA_OFFSET(8)
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH eax                      // pass arg1
-    call VAR(cxx_name, 1)     // cxx_name(arg1, Thread*, SP)
+    call VAR(cxx_name, 1)         // cxx_name(arg1, Thread*)
     addl MACRO_LITERAL(16), %esp  // pop arguments
     CFI_ADJUST_CFA_OFFSET(-16)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
     CALL_MACRO(return_macro, 2)   // return or deliver exception
     END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
 
 MACRO3(TWO_ARG_DOWNCALL, c_name, cxx_name, return_macro)
     DEFINE_FUNCTION RAW_VAR(c_name, 0)
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
-    mov %esp, %edx                // remember SP
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  ebx, ebx  // save ref containing registers for GC
     // Outgoing argument set up
-    PUSH edx                      // pass SP
+    PUSH eax                      // push padding
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH ecx                      // pass arg2
     PUSH eax                      // pass arg1
-    call VAR(cxx_name, 1)     // cxx_name(arg1, arg2, Thread*, SP)
+    call VAR(cxx_name, 1)         // cxx_name(arg1, arg2, Thread*)
     addl MACRO_LITERAL(16), %esp  // pop arguments
     CFI_ADJUST_CFA_OFFSET(-16)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
     CALL_MACRO(return_macro, 2)   // return or deliver exception
     END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
 
 MACRO3(THREE_ARG_DOWNCALL, c_name, cxx_name, return_macro)
     DEFINE_FUNCTION RAW_VAR(c_name, 0)
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
-    mov %esp, %ebx                // remember SP
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  ebx, ebx  // save ref containing registers for GC
     // Outgoing argument set up
-    subl MACRO_LITERAL(12), %esp  // alignment padding
-    CFI_ADJUST_CFA_OFFSET(12)
-    PUSH ebx                      // pass SP
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH edx                      // pass arg3
     PUSH ecx                      // pass arg2
     PUSH eax                      // pass arg1
-    call VAR(cxx_name, 1)     // cxx_name(arg1, arg2, arg3, Thread*, SP)
-    addl MACRO_LITERAL(32), %esp  // pop arguments
-    CFI_ADJUST_CFA_OFFSET(-32)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
+    call VAR(cxx_name, 1)         // cxx_name(arg1, arg2, arg3, Thread*)
+    addl MACRO_LITERAL(16), %esp  // pop arguments
+    CFI_ADJUST_CFA_OFFSET(-16)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
     CALL_MACRO(return_macro, 2)   // return or deliver exception
     END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
 
 MACRO3(ONE_ARG_REF_DOWNCALL, c_name, cxx_name, return_macro)
     DEFINE_FUNCTION RAW_VAR(c_name, 0)
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
-    mov %esp, %edx                // remember SP
-    mov 32(%esp), %ecx            // get referrer
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  ebx, ebx // save ref containing registers for GC
     // Outgoing argument set up
-    PUSH edx                      // pass SP
+    mov FRAME_SIZE_REFS_ONLY_CALLEE_SAVE(%esp), %ecx  // get referrer
+    PUSH eax                      // push padding
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH ecx                      // pass referrer
     PUSH eax                      // pass arg1
-    call VAR(cxx_name, 1)         // cxx_name(arg1, referrer, Thread*, SP)
+    call VAR(cxx_name, 1)         // cxx_name(arg1, referrer, Thread*)
     addl MACRO_LITERAL(16), %esp  // pop arguments
     CFI_ADJUST_CFA_OFFSET(-16)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
     CALL_MACRO(return_macro, 2)   // return or deliver exception
     END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
 
 MACRO3(TWO_ARG_REF_DOWNCALL, c_name, cxx_name, return_macro)
     DEFINE_FUNCTION RAW_VAR(c_name, 0)
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
-    mov %esp, %ebx                // remember SP
-    mov 32(%esp), %edx            // get referrer
-    subl MACRO_LITERAL(12), %esp  // alignment padding
-    CFI_ADJUST_CFA_OFFSET(12)
-    PUSH ebx                      // pass SP
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME ebx, ebx // save ref containing registers for GC
+    // Outgoing argument set up
+    mov FRAME_SIZE_REFS_ONLY_CALLEE_SAVE(%esp), %edx  // get referrer
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
-    // Outgoing argument set up
     PUSH edx                      // pass referrer
     PUSH ecx                      // pass arg2
     PUSH eax                      // pass arg1
-    call VAR(cxx_name, 1)     // cxx_name(arg1, arg2, referrer, Thread*, SP)
-    addl MACRO_LITERAL(32), %esp  // pop arguments
-    CFI_ADJUST_CFA_OFFSET(-32)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
+    call VAR(cxx_name, 1)         // cxx_name(arg1, arg2, referrer, Thread*)
+    addl MACRO_LITERAL(16), %esp  // pop arguments
+    CFI_ADJUST_CFA_OFFSET(-16)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
     CALL_MACRO(return_macro, 2)   // return or deliver exception
     END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
 
+MACRO3(THREE_ARG_REF_DOWNCALL, c_name, cxx_name, return_macro)
+    DEFINE_FUNCTION RAW_VAR(c_name, 0)
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME ebx, ebx  // save ref containing registers for GC
+    // Outgoing argument set up
+    mov FRAME_SIZE_REFS_ONLY_CALLEE_SAVE(%esp), %ebx  // get referrer
+    subl MACRO_LITERAL(12), %esp  // alignment padding
+    CFI_ADJUST_CFA_OFFSET(12)
+    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
+    CFI_ADJUST_CFA_OFFSET(4)
+    PUSH ebx                      // pass referrer
+    PUSH edx                      // pass arg3
+    PUSH ecx                      // pass arg2
+    PUSH eax                      // pass arg1
+    call VAR(cxx_name, 1)         // cxx_name(arg1, arg2, arg3, referrer, Thread*)
+    addl LITERAL(32), %esp        // pop arguments
+    CFI_ADJUST_CFA_OFFSET(-32)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
+    CALL_MACRO(return_macro, 2)   // return or deliver exception
+    END_FUNCTION RAW_VAR(c_name, 0)
+END_MACRO
 
 MACRO0(RETURN_IF_RESULT_IS_NON_ZERO)
     testl %eax, %eax               // eax == 0 ?
@@ -443,9 +479,8 @@
 END_MACRO
 
 MACRO0(RETURN_OR_DELIVER_PENDING_EXCEPTION)
-    mov %fs:THREAD_EXCEPTION_OFFSET, %ebx // get exception field
-    testl %ebx, %ebx               // ebx == 0 ?
-    jnz 1f                         // if ebx != 0 goto 1
+    cmpl MACRO_LITERAL(0),%fs:THREAD_EXCEPTION_OFFSET // exception field == 0 ?
+    jne 1f                         // if exception field != 0 goto 1
     ret                            // return
 1:                                 // deliver exception on current thread
     DELIVER_PENDING_EXCEPTION
@@ -566,7 +601,7 @@
     testl %eax, %eax                      // null check object/eax
     jz   .Lslow_lock
 .Lretry_lock:
-    movl LOCK_WORD_OFFSET(%eax), %ecx     // ecx := lock word
+    movl MIRROR_OBJECT_LOCK_WORD_OFFSET(%eax), %ecx  // ecx := lock word
     test LITERAL(0xC0000000), %ecx        // test the 2 high bits.
     jne  .Lslow_lock                      // slow path if either of the two high bits are set.
     movl %fs:THREAD_ID_OFFSET, %edx       // edx := thread id
@@ -575,11 +610,11 @@
     // unlocked case - %edx holds thread id with count of 0
     movl %eax, %ecx                       // remember object in case of retry
     xor  %eax, %eax                       // eax == 0 for comparison with lock word in cmpxchg
-    lock cmpxchg  %edx, LOCK_WORD_OFFSET(%ecx)
+    lock cmpxchg  %edx, MIRROR_OBJECT_LOCK_WORD_OFFSET(%ecx)
     jnz  .Lcmpxchg_fail                   // cmpxchg failed retry
     ret
 .Lcmpxchg_fail:
-    movl  %ecx, %eax                       // restore eax
+    movl  %ecx, %eax                      // restore eax
     jmp  .Lretry_lock
 .Lalready_thin:
     cmpw %cx, %dx                         // do we hold the lock already?
@@ -587,28 +622,28 @@
     addl LITERAL(65536), %ecx             // increment recursion count
     test LITERAL(0xC0000000), %ecx        // overflowed if either of top two bits are set
     jne  .Lslow_lock                      // count overflowed so go slow
-    movl %ecx, LOCK_WORD_OFFSET(%eax)     // update lockword, cmpxchg not necessary as we hold lock
+    // update lockword, cmpxchg not necessary as we hold lock
+    movl %ecx, MIRROR_OBJECT_LOCK_WORD_OFFSET(%eax)
     ret
 .Lslow_lock:
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
-    mov %esp, %edx                // remember SP
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  ebx, ebx  // save ref containing registers for GC
     // Outgoing argument set up
-    PUSH eax                      // push padding
-    PUSH edx                      // pass SP
+    subl LITERAL(8), %esp         // alignment padding
+    CFI_ADJUST_CFA_OFFSET(8)
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH eax                      // pass object
-    call SYMBOL(artLockObjectFromCode)  // artLockObjectFromCode(object, Thread*, SP)
+    call SYMBOL(artLockObjectFromCode)  // artLockObjectFromCode(object, Thread*)
     addl LITERAL(16), %esp  // pop arguments
     CFI_ADJUST_CFA_OFFSET(-16)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
     RETURN_IF_EAX_ZERO
 END_FUNCTION art_quick_lock_object
 
 DEFINE_FUNCTION art_quick_unlock_object
     testl %eax, %eax                      // null check object/eax
     jz   .Lslow_unlock
-    movl LOCK_WORD_OFFSET(%eax), %ecx     // ecx := lock word
+    movl MIRROR_OBJECT_LOCK_WORD_OFFSET(%eax), %ecx  // ecx := lock word
     movl %fs:THREAD_ID_OFFSET, %edx       // edx := thread id
     test LITERAL(0xC0000000), %ecx
     jnz  .Lslow_unlock                    // lock word contains a monitor
@@ -616,25 +651,24 @@
     jne  .Lslow_unlock
     cmpl LITERAL(65536), %ecx
     jae  .Lrecursive_thin_unlock
-    movl LITERAL(0), LOCK_WORD_OFFSET(%eax)
+    movl LITERAL(0), MIRROR_OBJECT_LOCK_WORD_OFFSET(%eax)
     ret
 .Lrecursive_thin_unlock:
     subl LITERAL(65536), %ecx
-    mov  %ecx, LOCK_WORD_OFFSET(%eax)
+    mov  %ecx, MIRROR_OBJECT_LOCK_WORD_OFFSET(%eax)
     ret
 .Lslow_unlock:
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
-    mov %esp, %edx                // remember SP
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  ebx, ebx  // save ref containing registers for GC
     // Outgoing argument set up
-    PUSH eax                      // push padding
-    PUSH edx                      // pass SP
+    subl LITERAL(8), %esp         // alignment padding
+    CFI_ADJUST_CFA_OFFSET(8)
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH eax                      // pass object
-    call SYMBOL(artUnlockObjectFromCode)  // artUnlockObjectFromCode(object, Thread*, SP)
+    call SYMBOL(artUnlockObjectFromCode)  // artUnlockObjectFromCode(object, Thread*)
     addl LITERAL(16), %esp  // pop arguments
     CFI_ADJUST_CFA_OFFSET(-16)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
     RETURN_IF_EAX_ZERO
 END_FUNCTION art_quick_unlock_object
 
@@ -663,15 +697,14 @@
     POP ecx
     addl LITERAL(4), %esp
     CFI_ADJUST_CFA_OFFSET(-12)
-    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
-    mov %esp, %edx
+    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  ebx, ebx  // save all registers as basis for long jump context
     // Outgoing argument set up
-    PUSH edx                      // pass SP
+    PUSH eax                      // alignment padding
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH ecx                      // pass arg2
     PUSH eax                      // pass arg1
-    call SYMBOL(artThrowClassCastException) // (Class* a, Class* b, Thread*, SP)
+    call SYMBOL(artThrowClassCastException) // (Class* a, Class* b, Thread*)
     int3                          // unreached
 END_FUNCTION art_quick_check_cast
 
@@ -687,7 +720,7 @@
 END_FUNCTION art_quick_aput_obj_with_null_and_bound_check
 
 DEFINE_FUNCTION art_quick_aput_obj_with_bound_check
-    movl ARRAY_LENGTH_OFFSET(%eax), %ebx
+    movl MIRROR_ARRAY_LENGTH_OFFSET(%eax), %ebx
     cmpl %ebx, %ecx
     jb SYMBOL(art_quick_aput_obj)
     mov %ecx, %eax
@@ -698,18 +731,19 @@
 DEFINE_FUNCTION art_quick_aput_obj
     test %edx, %edx              // store of null
     jz .Ldo_aput_null
-    movl CLASS_OFFSET(%eax), %ebx
-    movl CLASS_COMPONENT_TYPE_OFFSET(%ebx), %ebx
-    cmpl CLASS_OFFSET(%edx), %ebx // value's type == array's component type - trivial assignability
+    movl MIRROR_OBJECT_CLASS_OFFSET(%eax), %ebx
+    movl MIRROR_CLASS_COMPONENT_TYPE_OFFSET(%ebx), %ebx
+    // value's type == array's component type - trivial assignability
+    cmpl MIRROR_OBJECT_CLASS_OFFSET(%edx), %ebx
     jne .Lcheck_assignability
 .Ldo_aput:
-    movl %edx, OBJECT_ARRAY_DATA_OFFSET(%eax, %ecx, 4)
+    movl %edx, MIRROR_OBJECT_ARRAY_DATA_OFFSET(%eax, %ecx, 4)
     movl %fs:THREAD_CARD_TABLE_OFFSET, %edx
     shrl LITERAL(7), %eax
     movb %dl, (%edx, %eax)
     ret
 .Ldo_aput_null:
-    movl %edx, OBJECT_ARRAY_DATA_OFFSET(%eax, %ecx, 4)
+    movl %edx, MIRROR_OBJECT_ARRAY_DATA_OFFSET(%eax, %ecx, 4)
     ret
 .Lcheck_assignability:
     PUSH eax                     // save arguments
@@ -717,7 +751,7 @@
     PUSH edx
     subl LITERAL(8), %esp        // alignment padding
     CFI_ADJUST_CFA_OFFSET(8)
-    pushl CLASS_OFFSET(%edx)     // pass arg2 - type of the value to be stored
+    pushl MIRROR_OBJECT_CLASS_OFFSET(%edx)  // pass arg2 - type of the value to be stored
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH ebx                     // pass arg1 - component type of the array
     call SYMBOL(artIsAssignableFromCode)  // (Class* a, Class* b)
@@ -728,7 +762,7 @@
     POP  edx
     POP  ecx
     POP  eax
-    movl %edx, OBJECT_ARRAY_DATA_OFFSET(%eax, %ecx, 4)  // do the aput
+    movl %edx, MIRROR_OBJECT_ARRAY_DATA_OFFSET(%eax, %ecx, 4)  // do the aput
     movl %fs:THREAD_CARD_TABLE_OFFSET, %edx
     shrl LITERAL(7), %eax
     movb %dl, (%edx, %eax)
@@ -737,20 +771,19 @@
     POP  edx
     POP  ecx
     POP  eax
-    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
-    mov %esp, %ecx
+    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME ebx, ebx // save all registers as basis for long jump context
     // Outgoing argument set up
-    PUSH ecx                      // pass SP
+    PUSH eax                      // alignment padding
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH edx                      // pass arg2 - value
     PUSH eax                      // pass arg1 - array
-    call SYMBOL(artThrowArrayStoreException) // (array, value, Thread*, SP)
+    call SYMBOL(artThrowArrayStoreException) // (array, value, Thread*)
     int3                          // unreached
 END_FUNCTION art_quick_aput_obj
 
 DEFINE_FUNCTION art_quick_memcpy
-    SETUP_GOT_NOSAVE              // clobbers EBX
+    SETUP_GOT_NOSAVE ebx          // clobbers EBX
     PUSH edx                      // pass arg3
     PUSH ecx                      // pass arg2
     PUSH eax                      // pass arg1
@@ -856,236 +889,76 @@
     ret
 END_FUNCTION art_quick_lushr
 
-DEFINE_FUNCTION art_quick_set8_instance
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME       // save ref containing registers for GC
-    mov %esp, %ebx                // remember SP
-    subl LITERAL(8), %esp         // alignment padding
-    CFI_ADJUST_CFA_OFFSET(8)
-    PUSH ebx                      // pass SP
-    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
-    CFI_ADJUST_CFA_OFFSET(4)
-    mov 32(%ebx), %ebx            // get referrer
-    PUSH ebx                      // pass referrer
-    PUSH edx                      // pass new_val
-    PUSH ecx                      // pass object
-    PUSH eax                      // pass field_idx
-    call PLT_SYMBOL(artSet8InstanceFromCode)  // (field_idx, Object*, new_val, referrer, Thread*, SP)
-    addl LITERAL(32), %esp        // pop arguments
-    CFI_ADJUST_CFA_OFFSET(-32)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
-    RETURN_IF_EAX_ZERO            // return or deliver exception
-END_FUNCTION art_quick_set8_instance
+ONE_ARG_REF_DOWNCALL art_quick_get_boolean_static, artGetBooleanStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
+ONE_ARG_REF_DOWNCALL art_quick_get_byte_static, artGetByteStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
+ONE_ARG_REF_DOWNCALL art_quick_get_char_static, artGetCharStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
+ONE_ARG_REF_DOWNCALL art_quick_get_short_static, artGetShortStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
+ONE_ARG_REF_DOWNCALL art_quick_get32_static, artGet32StaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
+ONE_ARG_REF_DOWNCALL art_quick_get64_static, artGet64StaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
+ONE_ARG_REF_DOWNCALL art_quick_get_obj_static, artGetObjStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
 
-DEFINE_FUNCTION art_quick_set16_instance
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME       // save ref containing registers for GC
-    mov %esp, %ebx                // remember SP
-    subl LITERAL(8), %esp         // alignment padding
-    CFI_ADJUST_CFA_OFFSET(8)
-    PUSH ebx                      // pass SP
-    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
-    CFI_ADJUST_CFA_OFFSET(4)
-    mov 32(%ebx), %ebx            // get referrer
-    PUSH ebx                      // pass referrer
-    PUSH edx                      // pass new_val
-    PUSH ecx                      // pass object
-    PUSH eax                      // pass field_idx
-    call PLT_SYMBOL(artSet16InstanceFromCode)  // (field_idx, Object*, new_val, referrer, Thread*, SP)
-    addl LITERAL(32), %esp        // pop arguments
-    CFI_ADJUST_CFA_OFFSET(-32)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
-    RETURN_IF_EAX_ZERO            // return or deliver exception
-END_FUNCTION art_quick_set16_instance
+TWO_ARG_REF_DOWNCALL art_quick_get_boolean_instance, artGetBooleanInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
+TWO_ARG_REF_DOWNCALL art_quick_get_byte_instance, artGetByteInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
+TWO_ARG_REF_DOWNCALL art_quick_get_char_instance, artGetCharInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
+TWO_ARG_REF_DOWNCALL art_quick_get_short_instance, artGetShortInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
+TWO_ARG_REF_DOWNCALL art_quick_get32_instance, artGet32InstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
+TWO_ARG_REF_DOWNCALL art_quick_get64_instance, artGet64InstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
+TWO_ARG_REF_DOWNCALL art_quick_get_obj_instance, artGetObjInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
 
-DEFINE_FUNCTION art_quick_set32_instance
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME       // save ref containing registers for GC
-    mov %esp, %ebx                // remember SP
-    subl LITERAL(8), %esp         // alignment padding
-    CFI_ADJUST_CFA_OFFSET(8)
-    PUSH ebx                      // pass SP
-    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
-    CFI_ADJUST_CFA_OFFSET(4)
-    mov 32(%ebx), %ebx            // get referrer
-    PUSH ebx                      // pass referrer
-    PUSH edx                      // pass new_val
-    PUSH ecx                      // pass object
-    PUSH eax                      // pass field_idx
-    call SYMBOL(artSet32InstanceFromCode)  // (field_idx, Object*, new_val, referrer, Thread*, SP)
-    addl LITERAL(32), %esp        // pop arguments
-    CFI_ADJUST_CFA_OFFSET(-32)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
-    RETURN_IF_EAX_ZERO            // return or deliver exception
-END_FUNCTION art_quick_set32_instance
+TWO_ARG_REF_DOWNCALL art_quick_set8_static, artSet8StaticFromCode, RETURN_IF_EAX_ZERO
+TWO_ARG_REF_DOWNCALL art_quick_set16_static, artSet16StaticFromCode, RETURN_IF_EAX_ZERO
+TWO_ARG_REF_DOWNCALL art_quick_set32_static, artSet32StaticFromCode, RETURN_IF_EAX_ZERO
+TWO_ARG_REF_DOWNCALL art_quick_set_obj_static, artSetObjStaticFromCode, RETURN_IF_EAX_ZERO
 
+THREE_ARG_REF_DOWNCALL art_quick_set8_instance, artSet8InstanceFromCode, RETURN_IF_EAX_ZERO
+THREE_ARG_REF_DOWNCALL art_quick_set16_instance, artSet16InstanceFromCode, RETURN_IF_EAX_ZERO
+THREE_ARG_REF_DOWNCALL art_quick_set32_instance, artSet32InstanceFromCode, RETURN_IF_EAX_ZERO
+THREE_ARG_REF_DOWNCALL art_quick_set_obj_instance, artSetObjInstanceFromCode, RETURN_IF_EAX_ZERO
+
+// Call artSet64InstanceFromCode with 4 word size arguments and the referrer.
 DEFINE_FUNCTION art_quick_set64_instance
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME ebx, ebx  // save ref containing registers for GC
+    // Outgoing argument set up
+    mov FRAME_SIZE_REFS_ONLY_CALLEE_SAVE(%esp), %ebx  // get referrer
     subl LITERAL(8), %esp         // alignment padding
     CFI_ADJUST_CFA_OFFSET(8)
-    PUSH esp                      // pass SP-8
-    addl LITERAL(8), (%esp)       // fix SP on stack by adding 8
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
+    pushl (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE+12)(%esp)  // pass referrer
+    CFI_ADJUST_CFA_OFFSET(4)
     PUSH ebx                      // pass high half of new_val
     PUSH edx                      // pass low half of new_val
     PUSH ecx                      // pass object
     PUSH eax                      // pass field_idx
-    call SYMBOL(artSet64InstanceFromCode)  // (field_idx, Object*, new_val, Thread*, SP)
+    call SYMBOL(artSet64InstanceFromCode)  // (field_idx, Object*, new_val, referrer, Thread*)
     addl LITERAL(32), %esp        // pop arguments
     CFI_ADJUST_CFA_OFFSET(-32)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
     RETURN_IF_EAX_ZERO            // return or deliver exception
 END_FUNCTION art_quick_set64_instance
 
-DEFINE_FUNCTION art_quick_set_obj_instance
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
-    mov %esp, %ebx                // remember SP
-    subl LITERAL(8), %esp         // alignment padding
-    CFI_ADJUST_CFA_OFFSET(8)
-    PUSH ebx                      // pass SP
-    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
-    CFI_ADJUST_CFA_OFFSET(4)
-    mov 32(%ebx), %ebx            // get referrer
-    PUSH ebx                      // pass referrer
-    PUSH edx                      // pass new_val
-    PUSH ecx                      // pass object
-    PUSH eax                      // pass field_idx
-    call SYMBOL(artSetObjInstanceFromCode) // (field_idx, Object*, new_val, referrer, Thread*, SP)
-    addl LITERAL(32), %esp        // pop arguments
-    CFI_ADJUST_CFA_OFFSET(-32)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
-    RETURN_IF_EAX_ZERO            // return or deliver exception
-END_FUNCTION art_quick_set_obj_instance
-
-TWO_ARG_REF_DOWNCALL art_quick_get_byte_instance, artGetByteInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
-TWO_ARG_REF_DOWNCALL art_quick_get_boolean_instance, artGetBooleanInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
-TWO_ARG_REF_DOWNCALL art_quick_get_short_instance, artGetShortInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
-TWO_ARG_REF_DOWNCALL art_quick_get_char_instance, artGetCharInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
-TWO_ARG_REF_DOWNCALL art_quick_get32_instance, artGet32InstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
-TWO_ARG_REF_DOWNCALL art_quick_get_obj_instance, artGetObjInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
-
-DEFINE_FUNCTION art_quick_get64_instance
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME       // save ref containing registers for GC
-    mov %esp, %ebx                // remember SP
-    mov 32(%esp), %edx            // get referrer
-    subl LITERAL(12), %esp        // alignment padding
-    CFI_ADJUST_CFA_OFFSET(12)
-    PUSH ebx                      // pass SP
-    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
-    CFI_ADJUST_CFA_OFFSET(4)
-    PUSH edx                      // pass referrer
-    PUSH ecx                      // pass object
-    PUSH eax                      // pass field_idx
-    call SYMBOL(artGet64InstanceFromCode)  // (field_idx, Object*, referrer, Thread*, SP)
-    addl LITERAL(32), %esp        // pop arguments
-    CFI_ADJUST_CFA_OFFSET(-32)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
-    RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
-END_FUNCTION art_quick_get64_instance
-
-DEFINE_FUNCTION art_quick_set8_static
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME       // save ref containing registers for GC
-    mov %esp, %ebx                // remember SP
-    mov 32(%esp), %edx            // get referrer
-    subl LITERAL(12), %esp        // alignment padding
-    CFI_ADJUST_CFA_OFFSET(12)
-    PUSH ebx                      // pass SP
-    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
-    CFI_ADJUST_CFA_OFFSET(4)
-    PUSH edx                      // pass referrer
-    PUSH ecx                      // pass new_val
-    PUSH eax                      // pass field_idx
-    call SYMBOL(artSet8StaticFromCode)  // (field_idx, new_val, referrer, Thread*, SP)
-    addl LITERAL(32), %esp        // pop arguments
-    CFI_ADJUST_CFA_OFFSET(-32)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
-    RETURN_IF_EAX_ZERO            // return or deliver exception
-END_FUNCTION art_quick_set8_static
-
-DEFINE_FUNCTION art_quick_set16_static
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME       // save ref containing registers for GC
-    mov %esp, %ebx                // remember SP
-    mov 32(%esp), %edx            // get referrer
-    subl LITERAL(12), %esp        // alignment padding
-    CFI_ADJUST_CFA_OFFSET(12)
-    PUSH ebx                      // pass SP
-    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
-    CFI_ADJUST_CFA_OFFSET(4)
-    PUSH edx                      // pass referrer
-    PUSH ecx                      // pass new_val
-    PUSH eax                      // pass field_idx
-    call SYMBOL(artSet16StaticFromCode)  // (field_idx, new_val, referrer, Thread*, SP)
-    addl LITERAL(32), %esp        // pop arguments
-    CFI_ADJUST_CFA_OFFSET(-32)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
-    RETURN_IF_EAX_ZERO            // return or deliver exception
-END_FUNCTION art_quick_set16_static
-
-DEFINE_FUNCTION art_quick_set32_static
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME       // save ref containing registers for GC
-    mov %esp, %ebx                // remember SP
-    mov 32(%esp), %edx            // get referrer
-    subl LITERAL(12), %esp        // alignment padding
-    CFI_ADJUST_CFA_OFFSET(12)
-    PUSH ebx                      // pass SP
-    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
-    CFI_ADJUST_CFA_OFFSET(4)
-    PUSH edx                      // pass referrer
-    PUSH ecx                      // pass new_val
-    PUSH eax                      // pass field_idx
-    call SYMBOL(artSet32StaticFromCode)  // (field_idx, new_val, referrer, Thread*, SP)
-    addl LITERAL(32), %esp        // pop arguments
-    CFI_ADJUST_CFA_OFFSET(-32)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
-    RETURN_IF_EAX_ZERO            // return or deliver exception
-END_FUNCTION art_quick_set32_static
-
+// Call artSet64StaticFromCode with 3 word size arguments plus with the referrer in the 2nd position
+// so that new_val is aligned on even registers were we passing arguments in registers.
 DEFINE_FUNCTION art_quick_set64_static
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
-    mov %esp, %ebx                // remember SP
-    subl LITERAL(8), %esp         // alignment padding
-    CFI_ADJUST_CFA_OFFSET(8)
-    PUSH ebx                      // pass SP
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  ebx, ebx  // save ref containing registers for GC
+    mov FRAME_SIZE_REFS_ONLY_CALLEE_SAVE(%esp), %ebx  // get referrer
+    subl LITERAL(12), %esp        // alignment padding
+    CFI_ADJUST_CFA_OFFSET(12)
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
-    mov 32(%ebx), %ebx            // get referrer
     PUSH edx                      // pass high half of new_val
     PUSH ecx                      // pass low half of new_val
     PUSH ebx                      // pass referrer
     PUSH eax                      // pass field_idx
-    call SYMBOL(artSet64StaticFromCode)  // (field_idx, referrer, new_val, Thread*, SP)
+    call SYMBOL(artSet64StaticFromCode)  // (field_idx, referrer, new_val, Thread*)
     addl LITERAL(32), %esp        // pop arguments
     CFI_ADJUST_CFA_OFFSET(-32)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
     RETURN_IF_EAX_ZERO            // return or deliver exception
 END_FUNCTION art_quick_set64_static
 
-DEFINE_FUNCTION art_quick_set_obj_static
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
-    mov %esp, %ebx                // remember SP
-    mov 32(%esp), %edx            // get referrer
-    subl LITERAL(12), %esp        // alignment padding
-    CFI_ADJUST_CFA_OFFSET(12)
-    PUSH ebx                      // pass SP
-    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
-    CFI_ADJUST_CFA_OFFSET(4)
-    PUSH edx                      // pass referrer
-    PUSH ecx                      // pass new_val
-    PUSH eax                      // pass field_idx
-    call SYMBOL(artSetObjStaticFromCode)  // (field_idx, new_val, referrer, Thread*, SP)
-    addl LITERAL(32), %esp        // pop arguments
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
-    RETURN_IF_EAX_ZERO            // return or deliver exception
-END_FUNCTION art_quick_set_obj_static
-
-ONE_ARG_REF_DOWNCALL art_quick_get_byte_static, artGetByteStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
-ONE_ARG_REF_DOWNCALL art_quick_get_boolean_static, artGetBooleanStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
-ONE_ARG_REF_DOWNCALL art_quick_get_short_static, artGetShortStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
-ONE_ARG_REF_DOWNCALL art_quick_get_char_static, artGetCharStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
-ONE_ARG_REF_DOWNCALL art_quick_get32_static, artGet32StaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
-ONE_ARG_REF_DOWNCALL art_quick_get64_static, artGet64StaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
-ONE_ARG_REF_DOWNCALL art_quick_get_obj_static, artGetObjStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
-
 DEFINE_FUNCTION art_quick_proxy_invoke_handler
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME   // save frame and Method*
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_EAX
     PUSH esp                      // pass SP
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
@@ -1107,15 +980,15 @@
 DEFINE_FUNCTION art_quick_imt_conflict_trampoline
     PUSH ecx
     movl 8(%esp), %eax            // load caller Method*
-    movl METHOD_DEX_CACHE_METHODS_OFFSET(%eax), %eax  // load dex_cache_resolved_methods
+    movl MIRROR_ART_METHOD_DEX_CACHE_METHODS_OFFSET(%eax), %eax  // load dex_cache_resolved_methods
     movd %xmm0, %ecx              // get target method index stored in xmm0
-    movl OBJECT_ARRAY_DATA_OFFSET(%eax, %ecx, 4), %eax  // load the target method
+    movl MIRROR_OBJECT_ARRAY_DATA_OFFSET(%eax, %ecx, 4), %eax  // load the target method
     POP ecx
     jmp SYMBOL(art_quick_invoke_interface_trampoline)
 END_FUNCTION art_quick_imt_conflict_trampoline
 
 DEFINE_FUNCTION art_quick_resolution_trampoline
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME ebx, ebx
     movl %esp, %edi
     PUSH EDI                      // pass SP. do not just PUSH ESP; that messes up unwinding
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
@@ -1136,14 +1009,12 @@
     xchgl 0(%esp),%edi            // restore EDI and place code pointer as only value on stack
     ret                           // tail call into method
 1:
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     DELIVER_PENDING_EXCEPTION
 END_FUNCTION art_quick_resolution_trampoline
 
-DEFINE_FUNCTION_NO_HIDE art_quick_generic_jni_trampoline
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    // This also stores the native ArtMethod reference at the bottom of the stack.
-
+DEFINE_FUNCTION art_quick_generic_jni_trampoline
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_EAX
     movl %esp, %ebp                 // save SP at callee-save frame
     CFI_DEF_CFA_REGISTER(ebp)
     subl LITERAL(5120), %esp
@@ -1151,7 +1022,6 @@
     // (Thread*,  SP)
     //  (esp)    4(esp)   <= C calling convention
     //  fs:...    ebp     <= where they are
-    // Also: PLT, so need GOT in ebx.
 
     subl LITERAL(8), %esp         // Padding for 16B alignment.
     pushl %ebp                    // Pass SP (to ArtMethod).
@@ -1216,12 +1086,12 @@
     movl %ebp, %esp
     CFI_DEF_CFA_REGISTER(esp)
 .Lexception_in_native:
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     DELIVER_PENDING_EXCEPTION
 END_FUNCTION art_quick_generic_jni_trampoline
 
-DEFINE_FUNCTION_NO_HIDE art_quick_to_interpreter_bridge
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME   // save frame
+DEFINE_FUNCTION art_quick_to_interpreter_bridge
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME  ebx, ebx  // save frame
     mov %esp, %edx                // remember SP
     PUSH eax                      // alignment padding
     PUSH edx                      // pass SP
@@ -1234,7 +1104,7 @@
     punpckldq %xmm1, %xmm0
     addl LITERAL(16), %esp        // pop arguments
     CFI_ADJUST_CFA_OFFSET(-16)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
 END_FUNCTION art_quick_to_interpreter_bridge
 
@@ -1242,26 +1112,23 @@
      * Routine that intercepts method calls and returns.
      */
 DEFINE_FUNCTION art_quick_instrumentation_entry
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    movl  %esp, %edx              // Save SP.
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME ebx, edx
     PUSH eax                      // Save eax which will be clobbered by the callee-save method.
-    subl LITERAL(8), %esp         // Align stack.
-    CFI_ADJUST_CFA_OFFSET(8)
+    subl LITERAL(12), %esp        // Align stack.
+    CFI_ADJUST_CFA_OFFSET(12)
     pushl 40(%esp)                // Pass LR.
     CFI_ADJUST_CFA_OFFSET(4)
-    PUSH edx                      // Pass SP.
     pushl %fs:THREAD_SELF_OFFSET  // Pass Thread::Current().
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH ecx                      // Pass receiver.
     PUSH eax                      // Pass Method*.
-    call SYMBOL(artInstrumentationMethodEntryFromCode) // (Method*, Object*, Thread*, SP, LR)
-    SETUP_GOT_NOSAVE
+    call SYMBOL(artInstrumentationMethodEntryFromCode) // (Method*, Object*, Thread*, LR)
     addl LITERAL(28), %esp        // Pop arguments upto saved Method*.
     movl 28(%esp), %edi           // Restore edi.
     movl %eax, 28(%esp)           // Place code* over edi, just under return pc.
     movl SYMBOL(art_quick_instrumentation_exit)@GOT(%ebx), %ebx
+    // Place instrumentation exit as return pc. ebx holds the GOT computed on entry.
     movl %ebx, 32(%esp)
-                                  // Place instrumentation exit as return pc.
     movl (%esp), %eax             // Restore eax.
     movl 8(%esp), %ecx            // Restore ecx.
     movl 12(%esp), %edx           // Restore edx.
@@ -1274,7 +1141,7 @@
 
 DEFINE_FUNCTION art_quick_instrumentation_exit
     pushl LITERAL(0)              // Push a fake return PC as there will be none on the stack.
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME ebx, ebx
     mov  %esp, %ecx               // Remember SP
     subl LITERAL(8), %esp         // Save float return value.
     CFI_ADJUST_CFA_OFFSET(8)
@@ -1300,7 +1167,7 @@
     movq (%esp), %xmm0            // Restore fpr return value.
     addl LITERAL(8), %esp
     CFI_ADJUST_CFA_OFFSET(-8)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     addl LITERAL(4), %esp         // Remove fake return pc.
     jmp   *%ecx                   // Return.
 END_FUNCTION art_quick_instrumentation_exit
@@ -1311,14 +1178,12 @@
      */
 DEFINE_FUNCTION art_quick_deoptimize
     pushl %ebx                    // Fake that we were called.
-    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
-    mov  %esp, %ecx               // Remember SP.
-    subl LITERAL(8), %esp         // Align stack.
-    CFI_ADJUST_CFA_OFFSET(8)
-    PUSH ecx                      // Pass SP.
+    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME ebx, ebx
+    subl LITERAL(12), %esp        // Align stack.
+    CFI_ADJUST_CFA_OFFSET(12)
     pushl %fs:THREAD_SELF_OFFSET  // Pass Thread::Current().
     CFI_ADJUST_CFA_OFFSET(4)
-    call SYMBOL(artDeoptimize)  // artDeoptimize(Thread*, SP)
+    call SYMBOL(artDeoptimize)    // artDeoptimize(Thread*)
     int3                          // Unreachable.
 END_FUNCTION art_quick_deoptimize
 
@@ -1332,15 +1197,15 @@
 DEFINE_FUNCTION art_quick_string_compareto
     PUSH esi                    // push callee save reg
     PUSH edi                    // push callee save reg
-    mov STRING_COUNT_OFFSET(%eax), %edx
-    mov STRING_COUNT_OFFSET(%ecx), %ebx
-    mov STRING_VALUE_OFFSET(%eax), %esi
-    mov STRING_VALUE_OFFSET(%ecx), %edi
-    mov STRING_OFFSET_OFFSET(%eax), %eax
-    mov STRING_OFFSET_OFFSET(%ecx), %ecx
+    mov MIRROR_STRING_COUNT_OFFSET(%eax), %edx
+    mov MIRROR_STRING_COUNT_OFFSET(%ecx), %ebx
+    mov MIRROR_STRING_VALUE_OFFSET(%eax), %esi
+    mov MIRROR_STRING_VALUE_OFFSET(%ecx), %edi
+    mov MIRROR_STRING_OFFSET_OFFSET(%eax), %eax
+    mov MIRROR_STRING_OFFSET_OFFSET(%ecx), %ecx
     /* Build pointers to the start of string data */
-    lea  STRING_DATA_OFFSET(%esi, %eax, 2), %esi
-    lea  STRING_DATA_OFFSET(%edi, %ecx, 2), %edi
+    lea  MIRROR_CHAR_ARRAY_DATA_OFFSET(%esi, %eax, 2), %esi
+    lea  MIRROR_CHAR_ARRAY_DATA_OFFSET(%edi, %ecx, 2), %edi
     /* Calculate min length and count diff */
     mov   %edx, %ecx
     mov   %edx, %eax
@@ -1375,7 +1240,7 @@
 //  eax: address of jmp_buf in TLS
 
 DEFINE_FUNCTION art_nested_signal_return
-    SETUP_GOT_NOSAVE                // sets %ebx for call into PLT
+    SETUP_GOT_NOSAVE ebx            // sets %ebx for call into PLT
     movl LITERAL(1), %ecx
     pushl %ecx                      // second arg to longjmp (1)
     pushl %eax                      // first arg to longjmp (jmp_buf)
diff --git a/runtime/arch/x86_64/asm_support_x86_64.S b/runtime/arch/x86_64/asm_support_x86_64.S
index 4ae61a2..5964314 100644
--- a/runtime/arch/x86_64/asm_support_x86_64.S
+++ b/runtime/arch/x86_64/asm_support_x86_64.S
@@ -132,16 +132,6 @@
     CFI_DEF_CFA(rsp, 8)
 END_MACRO
 
-MACRO1(DEFINE_FUNCTION_NO_HIDE, c_name)
-    FUNCTION_TYPE(\c_name, 0)
-    .globl VAR(c_name, 0)
-    ALIGN_FUNCTION_ENTRY
-VAR(c_name, 0):
-    CFI_STARTPROC
-    // Ensure we get a sane starting CFA.
-    CFI_DEF_CFA(rsp, 8)
-END_MACRO
-
 MACRO1(END_FUNCTION, c_name)
     CFI_ENDPROC
     SIZE(\c_name, 0)
@@ -172,18 +162,6 @@
     SIZE(\name, 0)
 END_MACRO
 
-MACRO1(UNIMPLEMENTED_NO_HIDE,name)
-    FUNCTION_TYPE(\name, 0)
-    .globl VAR(name, 0)
-    ALIGN_FUNCTION_ENTRY
-VAR(name, 0):
-    CFI_STARTPROC
-    int3
-    int3
-    CFI_ENDPROC
-    SIZE(\name, 0)
-END_MACRO
-
 MACRO0(UNREACHABLE)
     int3
 END_MACRO
diff --git a/runtime/arch/x86_64/asm_support_x86_64.h b/runtime/arch/x86_64/asm_support_x86_64.h
index 40958dc..eddd172 100644
--- a/runtime/arch/x86_64/asm_support_x86_64.h
+++ b/runtime/arch/x86_64/asm_support_x86_64.h
@@ -19,30 +19,8 @@
 
 #include "asm_support.h"
 
-// Note: these callee save methods loads require read barriers.
-// Offset of field Runtime::callee_save_methods_[kSaveAll]
-#define RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET 0
-// Offset of field Runtime::callee_save_methods_[kRefsOnly]
-#define RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET 8
-// Offset of field Runtime::callee_save_methods_[kRefsAndArgs]
-#define RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET 16
-
-// Offset of field Thread::self_ verified in InitCpu
-#define THREAD_SELF_OFFSET 192
-// Offset of field Thread::card_table_ verified in InitCpu
-#define THREAD_CARD_TABLE_OFFSET 120
-// Offset of field Thread::exception_ verified in InitCpu
-#define THREAD_EXCEPTION_OFFSET 128
-// Offset of field Thread::thin_lock_thread_id_ verified in InitCpu
-#define THREAD_ID_OFFSET 12
-
 #define FRAME_SIZE_SAVE_ALL_CALLEE_SAVE 64 + 4*8
 #define FRAME_SIZE_REFS_ONLY_CALLEE_SAVE 64 + 4*8
 #define FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE 176 + 4*8
 
-// Expected size of a heap reference
-#define HEAP_REFERENCE_SIZE 4
-// Expected size of a stack reference
-#define STACK_REFERENCE_SIZE 4
-
 #endif  // ART_RUNTIME_ARCH_X86_64_ASM_SUPPORT_X86_64_H_
diff --git a/runtime/arch/x86_64/entrypoints_init_x86_64.cc b/runtime/arch/x86_64/entrypoints_init_x86_64.cc
index c9028e1..be73594 100644
--- a/runtime/arch/x86_64/entrypoints_init_x86_64.cc
+++ b/runtime/arch/x86_64/entrypoints_init_x86_64.cc
@@ -19,19 +19,12 @@
 #include "entrypoints/portable/portable_entrypoints.h"
 #include "entrypoints/quick/quick_alloc_entrypoints.h"
 #include "entrypoints/quick/quick_entrypoints.h"
-#include "entrypoints/entrypoint_utils.h"
 #include "entrypoints/math_entrypoints.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
+#include "interpreter/interpreter.h"
 
 namespace art {
 
-// Interpreter entrypoints.
-extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh,
-                                                  const DexFile::CodeItem* code_item,
-                                                  ShadowFrame* shadow_frame, JValue* result);
-extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh,
-                                                   const DexFile::CodeItem* code_item,
-                                                   ShadowFrame* shadow_frame, JValue* result);
-
 // Portable entrypoints.
 extern "C" void art_portable_resolution_trampoline(mirror::ArtMethod*);
 extern "C" void art_portable_to_interpreter_bridge(mirror::ArtMethod*);
diff --git a/runtime/arch/x86_64/portable_entrypoints_x86_64.S b/runtime/arch/x86_64/portable_entrypoints_x86_64.S
index 7b84d17..3a54005 100644
--- a/runtime/arch/x86_64/portable_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/portable_entrypoints_x86_64.S
@@ -25,4 +25,6 @@
 
 UNIMPLEMENTED art_portable_resolution_trampoline
 
-UNIMPLEMENTED_NO_HIDE art_portable_to_interpreter_bridge
+UNIMPLEMENTED art_portable_to_interpreter_bridge
+
+UNIMPLEMENTED art_portable_imt_conflict_trampoline
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index ca9c0bf..bed7238 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -57,25 +57,25 @@
     PUSH r12  // Callee save.
     PUSH rbp  // Callee save.
     PUSH rbx  // Callee save.
-    // Create space for FPR args, plus padding for alignment
-    subq LITERAL(4 * 8), %rsp
-    CFI_ADJUST_CFA_OFFSET(4 * 8)
+    // Create space for FPR args, plus space for StackReference<ArtMethod>.
+    subq MACRO_LITERAL(4 * 8 + 8), %rsp
+    CFI_ADJUST_CFA_OFFSET(4 * 8 + 8)
     // Save FPRs.
-    movq %xmm12, 0(%rsp)
-    movq %xmm13, 8(%rsp)
-    movq %xmm14, 16(%rsp)
-    movq %xmm15, 24(%rsp)
-    subq MACRO_LITERAL(8), %rsp  // Space for Method* (also aligns the frame).
-    CFI_ADJUST_CFA_OFFSET(8)
+    movq %xmm12, 8(%rsp)
+    movq %xmm13, 16(%rsp)
+    movq %xmm14, 24(%rsp)
+    movq %xmm15, 32(%rsp)
     // R10 := ArtMethod* for save all callee save frame method.
     THIS_LOAD_REQUIRES_READ_BARRIER
     movq RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET(%r10), %r10
     // Store ArtMethod* to bottom of stack.
     movq %r10, 0(%rsp)
+    // Store rsp as the top quick frame.
+    movq %rsp, %gs:THREAD_TOP_QUICK_FRAME_OFFSET
 
     // Ugly compile-time check, but we only have the preprocessor.
     // Last +8: implicit return address pushed on stack when caller made call.
-#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 6*8 + 4*8 + 8 + 8)
+#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 6 * 8 + 4 * 8 + 8 + 8)
 #error "SAVE_ALL_CALLEE_SAVE_FRAME(X86_64) size not as expected."
 #endif
 #endif  // __APPLE__
@@ -85,7 +85,7 @@
      * Macro that sets up the callee save frame to conform with
      * Runtime::CreateCalleeSaveMethod(kRefsOnly)
      */
-MACRO0(SETUP_REF_ONLY_CALLEE_SAVE_FRAME)
+MACRO0(SETUP_REFS_ONLY_CALLEE_SAVE_FRAME)
 #if defined(__APPLE__)
     int3
     int3
@@ -100,9 +100,9 @@
     PUSH r12  // Callee save.
     PUSH rbp  // Callee save.
     PUSH rbx  // Callee save.
-    // Create space for FPR args, plus padding for alignment
-    subq LITERAL(8 + 4*8), %rsp
-    CFI_ADJUST_CFA_OFFSET(8 + 4*8)
+    // Create space for FPR args, plus space for StackReference<ArtMethod>.
+    subq LITERAL(8 + 4 * 8), %rsp
+    CFI_ADJUST_CFA_OFFSET(8 + 4 * 8)
     // Save FPRs.
     movq %xmm12, 8(%rsp)
     movq %xmm13, 16(%rsp)
@@ -113,16 +113,18 @@
     movq RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET(%r10), %r10
     // Store ArtMethod* to bottom of stack.
     movq %r10, 0(%rsp)
+    // Store rsp as the stop quick frame.
+    movq %rsp, %gs:THREAD_TOP_QUICK_FRAME_OFFSET
 
     // Ugly compile-time check, but we only have the preprocessor.
     // Last +8: implicit return address pushed on stack when caller made call.
-#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 6*8 + 4*8 + 8 + 8)
+#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 6 * 8 + 4 * 8 + 8 + 8)
 #error "REFS_ONLY_CALLEE_SAVE_FRAME(X86_64) size not as expected."
 #endif
 #endif  // __APPLE__
 END_MACRO
 
-MACRO0(RESTORE_REF_ONLY_CALLEE_SAVE_FRAME)
+MACRO0(RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME)
     movq 8(%rsp), %xmm12
     movq 16(%rsp), %xmm13
     movq 24(%rsp), %xmm14
@@ -142,7 +144,7 @@
      * Macro that sets up the callee save frame to conform with
      * Runtime::CreateCalleeSaveMethod(kRefsAndArgs)
      */
-MACRO0(SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME)
+MACRO0(SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME)
 #if defined(__APPLE__)
     int3
     int3
@@ -162,12 +164,13 @@
     PUSH rbx  // Callee save.
     PUSH rdx  // Quick arg 2.
     PUSH rcx  // Quick arg 3.
-    // Create space for FPR args and create 2 slots, 1 of padding and 1 for the ArtMethod*.
+    // Create space for FPR args and create 2 slots, 1 of padding and 1 for the
+    // StackReference<ArtMethod>.
     subq MACRO_LITERAL(80 + 4 * 8), %rsp
     CFI_ADJUST_CFA_OFFSET(80 + 4 * 8)
     // R10 := ArtMethod* for ref and args callee save frame method.
     THIS_LOAD_REQUIRES_READ_BARRIER
-    movq RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET(%r10), %r10
+    movq RUNTIME_REFS_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET(%r10), %r10
     // Save FPRs.
     movq %xmm0, 16(%rsp)
     movq %xmm1, 24(%rsp)
@@ -183,16 +186,54 @@
     movq %xmm15, 104(%rsp)
     // Store ArtMethod* to bottom of stack.
     movq %r10, 0(%rsp)
+    // Store rsp as the top quick frame.
+    movq %rsp, %gs:THREAD_TOP_QUICK_FRAME_OFFSET
 
     // Ugly compile-time check, but we only have the preprocessor.
     // Last +8: implicit return address pushed on stack when caller made call.
-#if (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE != 11*8 + 4*8 + 80 + 8)
+#if (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE != 11 * 8 + 4 * 8 + 80 + 8)
 #error "REFS_AND_ARGS_CALLEE_SAVE_FRAME(X86_64) size not as expected."
 #endif
 #endif  // __APPLE__
 END_MACRO
 
-MACRO0(RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME)
+MACRO0(SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_RDI)
+    // Save callee and GPR args, mixed together to agree with core spills bitmap.
+    PUSH r15  // Callee save.
+    PUSH r14  // Callee save.
+    PUSH r13  // Callee save.
+    PUSH r12  // Callee save.
+    PUSH r9   // Quick arg 5.
+    PUSH r8   // Quick arg 4.
+    PUSH rsi  // Quick arg 1.
+    PUSH rbp  // Callee save.
+    PUSH rbx  // Callee save.
+    PUSH rdx  // Quick arg 2.
+    PUSH rcx  // Quick arg 3.
+    // Create space for FPR args and create 2 slots, 1 of padding and 1 for the
+    // StackReference<ArtMethod>.
+    subq LITERAL(80 + 4 * 8), %rsp
+    CFI_ADJUST_CFA_OFFSET(80 + 4 * 8)
+    // Save FPRs.
+    movq %xmm0, 16(%rsp)
+    movq %xmm1, 24(%rsp)
+    movq %xmm2, 32(%rsp)
+    movq %xmm3, 40(%rsp)
+    movq %xmm4, 48(%rsp)
+    movq %xmm5, 56(%rsp)
+    movq %xmm6, 64(%rsp)
+    movq %xmm7, 72(%rsp)
+    movq %xmm12, 80(%rsp)
+    movq %xmm13, 88(%rsp)
+    movq %xmm14, 96(%rsp)
+    movq %xmm15, 104(%rsp)
+    // Store ArtMethod to bottom of stack.
+    movq %rdi, 0(%rsp)
+    // Store rsp as the stop quick frame.
+    movq %rsp, %gs:THREAD_TOP_QUICK_FRAME_OFFSET
+END_MACRO
+
+MACRO0(RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME)
     // Restore FPRs.
     movq 16(%rsp), %xmm0
     movq 24(%rsp), %xmm1
@@ -229,10 +270,9 @@
      */
 MACRO0(DELIVER_PENDING_EXCEPTION)
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME         // save callee saves for throw
-    // (Thread*, SP) setup
+    // (Thread*) setup
     movq %gs:THREAD_SELF_OFFSET, %rdi
-    movq %rsp, %rsi
-    call SYMBOL(artDeliverPendingExceptionFromCode)  // artDeliverPendingExceptionFromCode(Thread*, SP)
+    call SYMBOL(artDeliverPendingExceptionFromCode)  // artDeliverPendingExceptionFromCode(Thread*)
     UNREACHABLE
 END_MACRO
 
@@ -240,9 +280,8 @@
     DEFINE_FUNCTION VAR(c_name, 0)
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
     // Outgoing argument set up
-    movq %rsp, %rsi                    // pass SP
     movq %gs:THREAD_SELF_OFFSET, %rdi  // pass Thread::Current()
-    call VAR(cxx_name, 1)     // cxx_name(Thread*, SP)
+    call VAR(cxx_name, 1)     // cxx_name(Thread*)
     UNREACHABLE
     END_FUNCTION VAR(c_name, 0)
 END_MACRO
@@ -251,9 +290,8 @@
     DEFINE_FUNCTION VAR(c_name, 0)
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
     // Outgoing argument set up
-    movq %rsp, %rdx                    // pass SP
     movq %gs:THREAD_SELF_OFFSET, %rsi  // pass Thread::Current()
-    call VAR(cxx_name, 1)     // cxx_name(arg1, Thread*, SP)
+    call VAR(cxx_name, 1)     // cxx_name(arg1, Thread*)
     UNREACHABLE
     END_FUNCTION VAR(c_name, 0)
 END_MACRO
@@ -262,9 +300,8 @@
     DEFINE_FUNCTION VAR(c_name, 0)
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
     // Outgoing argument set up
-    movq %rsp, %rcx                    // pass SP
     movq %gs:THREAD_SELF_OFFSET, %rdx  // pass Thread::Current()
-    call VAR(cxx_name, 1)     // cxx_name(Thread*, SP)
+    call VAR(cxx_name, 1)     // cxx_name(Thread*)
     UNREACHABLE
     END_FUNCTION VAR(c_name, 0)
 END_MACRO
@@ -321,7 +358,7 @@
      */
 MACRO2(INVOKE_TRAMPOLINE, c_name, cxx_name)
     DEFINE_FUNCTION VAR(c_name, 0)
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME  // save callee saves in case allocation triggers GC
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME  // save callee saves in case allocation triggers GC
     // Helper signature is always
     // (method_idx, *this_object, *caller_method, *self, sp)
 
@@ -333,7 +370,7 @@
                                                            // save the code pointer
     movq %rax, %rdi
     movq %rdx, %rax
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
 
     testq %rdi, %rdi
     jz 1f
@@ -481,7 +518,7 @@
     LOOP_OVER_SHORTY_LOADING_GPRS r8, r8d, .Lgpr_setup_finished
     LOOP_OVER_SHORTY_LOADING_GPRS r9, r9d, .Lgpr_setup_finished
 .Lgpr_setup_finished:
-    call *METHOD_QUICK_CODE_OFFSET(%rdi) // Call the method.
+    call *MIRROR_ART_METHOD_QUICK_CODE_OFFSET(%rdi) // Call the method.
     movq %rbp, %rsp               // Restore stack pointer.
     CFI_DEF_CFA_REGISTER(rsp)
     POP r9                        // Pop r9 - shorty*.
@@ -564,7 +601,7 @@
     LOOP_OVER_SHORTY_LOADING_GPRS r8, r8d, .Lgpr_setup_finished2
     LOOP_OVER_SHORTY_LOADING_GPRS r9, r9d, .Lgpr_setup_finished2
 .Lgpr_setup_finished2:
-    call *METHOD_QUICK_CODE_OFFSET(%rdi) // Call the method.
+    call *MIRROR_ART_METHOD_QUICK_CODE_OFFSET(%rdi) // Call the method.
     movq %rbp, %rsp               // Restore stack pointer.
     CFI_DEF_CFA_REGISTER(rsp)
     POP r9                        // Pop r9 - shorty*.
@@ -639,88 +676,81 @@
 
 MACRO3(NO_ARG_DOWNCALL, c_name, cxx_name, return_macro)
     DEFINE_FUNCTION VAR(c_name, 0)
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    // save ref containing registers for GC
     // Outgoing argument set up
-    movq %rsp, %rsi                   // pass SP
-    movq %gs:THREAD_SELF_OFFSET, %rdi // pass Thread::Current()
-    call VAR(cxx_name, 1)         // cxx_name(Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
-    CALL_MACRO(return_macro, 2)       // return or deliver exception
+    movq %gs:THREAD_SELF_OFFSET, %rdi    // pass Thread::Current()
+    call VAR(cxx_name, 1)                // cxx_name(Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
+    CALL_MACRO(return_macro, 2)          // return or deliver exception
     END_FUNCTION VAR(c_name, 0)
 END_MACRO
 
 MACRO3(ONE_ARG_DOWNCALL, c_name, cxx_name, return_macro)
     DEFINE_FUNCTION VAR(c_name, 0)
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME   // save ref containing registers for GC
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    // save ref containing registers for GC
     // Outgoing argument set up
-    movq %rsp, %rdx                    // pass SP
-    movq %gs:THREAD_SELF_OFFSET, %rsi  // pass Thread::Current()
-    call VAR(cxx_name, 1)          // cxx_name(arg0, Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
-    CALL_MACRO(return_macro, 2)        // return or deliver exception
+    movq %gs:THREAD_SELF_OFFSET, %rsi    // pass Thread::Current()
+    call VAR(cxx_name, 1)                // cxx_name(arg0, Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
+    CALL_MACRO(return_macro, 2)          // return or deliver exception
     END_FUNCTION VAR(c_name, 0)
 END_MACRO
 
 MACRO3(TWO_ARG_DOWNCALL, c_name, cxx_name, return_macro)
     DEFINE_FUNCTION VAR(c_name, 0)
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME   // save ref containing registers for GC
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    // save ref containing registers for GC
     // Outgoing argument set up
-    movq %rsp, %rcx                    // pass SP
-    movq %gs:THREAD_SELF_OFFSET, %rdx  // pass Thread::Current()
-    call VAR(cxx_name, 1)          // cxx_name(arg0, arg1, Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
-    CALL_MACRO(return_macro, 2)       // return or deliver exception
+    movq %gs:THREAD_SELF_OFFSET, %rdx    // pass Thread::Current()
+    call VAR(cxx_name, 1)                // cxx_name(arg0, arg1, Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
+    CALL_MACRO(return_macro, 2)          // return or deliver exception
     END_FUNCTION VAR(c_name, 0)
 END_MACRO
 
 MACRO3(THREE_ARG_DOWNCALL, c_name, cxx_name, return_macro)
     DEFINE_FUNCTION VAR(c_name, 0)
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME   // save ref containing registers for GC
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME   // save ref containing registers for GC
     // Outgoing argument set up
-    movq %rsp, %r8                     // pass SP
-    movq %gs:THREAD_SELF_OFFSET, %rcx  // pass Thread::Current()
-    call VAR(cxx_name, 1)          // cxx_name(arg0, arg1, arg2, Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
-    CALL_MACRO(return_macro, 2)        // return or deliver exception
+    movq %gs:THREAD_SELF_OFFSET, %rcx   // pass Thread::Current()
+    call VAR(cxx_name, 1)               // cxx_name(arg0, arg1, arg2, Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+    CALL_MACRO(return_macro, 2)         // return or deliver exception
     END_FUNCTION VAR(c_name, 0)
 END_MACRO
 
 MACRO3(ONE_ARG_REF_DOWNCALL, c_name, cxx_name, return_macro)
     DEFINE_FUNCTION VAR(c_name, 0)
-    movl 8(%rsp), %esi                 // pass referrer
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
-                                       // arg0 is in rdi
-    movq %gs:THREAD_SELF_OFFSET, %rdx  // pass Thread::Current()
-    movq %rsp, %rcx                    // pass SP
-    call VAR(cxx_name, 1)          // cxx_name(arg0, referrer, Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+    movl 8(%rsp), %esi                  // pass referrer
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME
+                                        // arg0 is in rdi
+    movq %gs:THREAD_SELF_OFFSET, %rdx   // pass Thread::Current()
+    call VAR(cxx_name, 1)               // cxx_name(arg0, referrer, Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
     CALL_MACRO(return_macro, 2)
     END_FUNCTION VAR(c_name, 0)
 END_MACRO
 
 MACRO3(TWO_ARG_REF_DOWNCALL, c_name, cxx_name, return_macro)
     DEFINE_FUNCTION VAR(c_name, 0)
-    movl 8(%rsp), %edx                 // pass referrer
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
-                                       // arg0 and arg1 are in rdi/rsi
-    movq %gs:THREAD_SELF_OFFSET, %rcx  // pass Thread::Current()
-    movq %rsp, %r8                     // pass SP
-    call VAR(cxx_name, 1)          // (arg0, arg1, referrer, Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+    movl 8(%rsp), %edx                  // pass referrer
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME
+                                        // arg0 and arg1 are in rdi/rsi
+    movq %gs:THREAD_SELF_OFFSET, %rcx   // pass Thread::Current()
+    call VAR(cxx_name, 1)               // (arg0, arg1, referrer, Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
     CALL_MACRO(return_macro, 2)
     END_FUNCTION VAR(c_name, 0)
 END_MACRO
 
 MACRO3(THREE_ARG_REF_DOWNCALL, c_name, cxx_name, return_macro)
     DEFINE_FUNCTION VAR(c_name, 0)
-    movl 8(%rsp), %ecx                 // pass referrer
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
-                                       // arg0, arg1, and arg2 are in rdi/rsi/rdx
+    movl 8(%rsp), %ecx                  // pass referrer
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME
+                                        // arg0, arg1, and arg2 are in rdi/rsi/rdx
     movq %gs:THREAD_SELF_OFFSET, %r8    // pass Thread::Current()
-    movq %rsp, %r9                     // pass SP
-    call VAR(cxx_name, 1)          // cxx_name(arg0, arg1, arg2, referrer, Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
-    CALL_MACRO(return_macro, 2)        // return or deliver exception
+    call VAR(cxx_name, 1)               // cxx_name(arg0, arg1, arg2, referrer, Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+    CALL_MACRO(return_macro, 2)         // return or deliver exception
     END_FUNCTION VAR(c_name, 0)
 END_MACRO
 
@@ -864,7 +894,7 @@
     testl %edi, %edi                      // Null check object/rdi.
     jz   .Lslow_lock
 .Lretry_lock:
-    movl LOCK_WORD_OFFSET(%edi), %ecx     // ecx := lock word.
+    movl MIRROR_OBJECT_LOCK_WORD_OFFSET(%edi), %ecx  // ecx := lock word.
     test LITERAL(0xC0000000), %ecx        // Test the 2 high bits.
     jne  .Lslow_lock                      // Slow path if either of the two high bits are set.
     movl %gs:THREAD_ID_OFFSET, %edx       // edx := thread id
@@ -872,7 +902,7 @@
     jnz  .Lalready_thin                   // Lock word contains a thin lock.
     // unlocked case - %edx holds thread id with count of 0
     xor  %eax, %eax                       // eax == 0 for comparison with lock word in cmpxchg
-    lock cmpxchg  %edx, LOCK_WORD_OFFSET(%edi)
+    lock cmpxchg  %edx, MIRROR_OBJECT_LOCK_WORD_OFFSET(%edi)
     jnz  .Lretry_lock                     // cmpxchg failed retry
     ret
 .Lalready_thin:
@@ -881,21 +911,21 @@
     addl LITERAL(65536), %ecx             // increment recursion count
     test LITERAL(0xC0000000), %ecx        // overflowed if either of top two bits are set
     jne  .Lslow_lock                      // count overflowed so go slow
-    movl %ecx, LOCK_WORD_OFFSET(%edi)     // update lockword, cmpxchg not necessary as we hold lock
+    // update lockword, cmpxchg not necessary as we hold lock
+    movl %ecx, MIRROR_OBJECT_LOCK_WORD_OFFSET(%edi)
     ret
 .Lslow_lock:
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME
     movq %gs:THREAD_SELF_OFFSET, %rsi     // pass Thread::Current()
-    movq %rsp, %rdx                       // pass SP
-    call SYMBOL(artLockObjectFromCode)  // artLockObjectFromCode(object, Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME    // restore frame up to return address
+    call SYMBOL(artLockObjectFromCode)    // artLockObjectFromCode(object, Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME   // restore frame up to return address
     RETURN_IF_EAX_ZERO
 END_FUNCTION art_quick_lock_object
 
 DEFINE_FUNCTION art_quick_unlock_object
     testl %edi, %edi                      // null check object/edi
     jz   .Lslow_unlock
-    movl LOCK_WORD_OFFSET(%edi), %ecx     // ecx := lock word
+    movl MIRROR_OBJECT_LOCK_WORD_OFFSET(%edi), %ecx  // ecx := lock word
     movl %gs:THREAD_ID_OFFSET, %edx       // edx := thread id
     test LITERAL(0xC0000000), %ecx
     jnz  .Lslow_unlock                    // lock word contains a monitor
@@ -903,18 +933,17 @@
     jne  .Lslow_unlock
     cmpl LITERAL(65536), %ecx
     jae  .Lrecursive_thin_unlock
-    movl LITERAL(0), LOCK_WORD_OFFSET(%edi)
+    movl LITERAL(0), MIRROR_OBJECT_LOCK_WORD_OFFSET(%edi)
     ret
 .Lrecursive_thin_unlock:
     subl LITERAL(65536), %ecx
-    mov  %ecx, LOCK_WORD_OFFSET(%edi)
+    mov  %ecx, MIRROR_OBJECT_LOCK_WORD_OFFSET(%edi)
     ret
 .Lslow_unlock:
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME
     movq %gs:THREAD_SELF_OFFSET, %rsi     // pass Thread::Current()
-    movq %rsp, %rdx                       // pass SP
-    call SYMBOL(artUnlockObjectFromCode)  // artUnlockObjectFromCode(object, Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME    // restore frame up to return address
+    call SYMBOL(artUnlockObjectFromCode)  // artUnlockObjectFromCode(object, Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME   // restore frame up to return address
     RETURN_IF_EAX_ZERO
 END_FUNCTION art_quick_unlock_object
 
@@ -935,9 +964,8 @@
     POP rsi                           // Pop arguments
     POP rdi
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
-    mov %rsp, %rcx                    // pass SP
     mov %gs:THREAD_SELF_OFFSET, %rdx  // pass Thread::Current()
-    call SYMBOL(artThrowClassCastException) // (Class* a, Class* b, Thread*, SP)
+    call SYMBOL(artThrowClassCastException) // (Class* a, Class* b, Thread*)
     int3                              // unreached
 END_FUNCTION art_quick_check_cast
 
@@ -969,8 +997,8 @@
     int3
     int3
 #else
-    movl ARRAY_LENGTH_OFFSET(%edi), %ecx
-//  movl ARRAY_LENGTH_OFFSET(%rdi), %ecx      // This zero-extends, so value(%rcx)=value(%ecx)
+    movl MIRROR_ARRAY_LENGTH_OFFSET(%edi), %ecx
+//  movl MIRROR_ARRAY_LENGTH_OFFSET(%rdi), %ecx  // This zero-extends, so value(%rcx)=value(%ecx)
     cmpl %ecx, %esi
     jb art_quick_aput_obj
     mov %esi, %edi
@@ -986,24 +1014,24 @@
     testl %edx, %edx                // store of null
 //  test %rdx, %rdx
     jz .Ldo_aput_null
-    movl CLASS_OFFSET(%edi), %ecx
-//  movq CLASS_OFFSET(%rdi), %rcx
-    movl CLASS_COMPONENT_TYPE_OFFSET(%ecx), %ecx
-//  movq CLASS_COMPONENT_TYPE_OFFSET(%rcx), %rcx
-    cmpl CLASS_OFFSET(%edx), %ecx // value's type == array's component type - trivial assignability
-//  cmpq CLASS_OFFSET(%rdx), %rcx
+    movl MIRROR_OBJECT_CLASS_OFFSET(%edi), %ecx
+//  movq MIRROR_OBJECT_CLASS_OFFSET(%rdi), %rcx
+    movl MIRROR_CLASS_COMPONENT_TYPE_OFFSET(%ecx), %ecx
+//  movq MIRROR_CLASS_COMPONENT_TYPE_OFFSET(%rcx), %rcx
+    cmpl MIRROR_OBJECT_CLASS_OFFSET(%edx), %ecx // value's type == array's component type - trivial assignability
+//  cmpq MIRROR_CLASS_OFFSET(%rdx), %rcx
     jne .Lcheck_assignability
 .Ldo_aput:
-    movl %edx, OBJECT_ARRAY_DATA_OFFSET(%edi, %esi, 4)
-//  movq %rdx, OBJECT_ARRAY_DATA_OFFSET(%rdi, %rsi, 4)
+    movl %edx, MIRROR_OBJECT_ARRAY_DATA_OFFSET(%edi, %esi, 4)
+//  movq %rdx, MIRROR_OBJECT_ARRAY_DATA_OFFSET(%rdi, %rsi, 4)
     movq %gs:THREAD_CARD_TABLE_OFFSET, %rdx
     shrl LITERAL(7), %edi
 //  shrl LITERAL(7), %rdi
     movb %dl, (%rdx, %rdi)                       // Note: this assumes that top 32b of %rdi are zero
     ret
 .Ldo_aput_null:
-    movl %edx, OBJECT_ARRAY_DATA_OFFSET(%edi, %esi, 4)
-//  movq %rdx, OBJECT_ARRAY_DATA_OFFSET(%rdi, %rsi, 4)
+    movl %edx, MIRROR_OBJECT_ARRAY_DATA_OFFSET(%edi, %esi, 4)
+//  movq %rdx, MIRROR_OBJECT_ARRAY_DATA_OFFSET(%rdi, %rsi, 4)
     ret
 .Lcheck_assignability:
     // Save arguments.
@@ -1015,7 +1043,7 @@
     SETUP_FP_CALLEE_SAVE_FRAME
 
                                   // "Uncompress" = do nothing, as already zero-extended on load.
-    movl CLASS_OFFSET(%edx), %esi // Pass arg2 = value's class.
+    movl MIRROR_OBJECT_CLASS_OFFSET(%edx), %esi // Pass arg2 = value's class.
     movq %rcx, %rdi               // Pass arg1 = array's component type.
 
     call SYMBOL(artIsAssignableFromCode)  // (Class* a, Class* b)
@@ -1032,8 +1060,8 @@
     POP  rsi
     POP  rdi
 
-    movl %edx, OBJECT_ARRAY_DATA_OFFSET(%edi, %esi, 4)
-//  movq %rdx, OBJECT_ARRAY_DATA_OFFSET(%rdi, %rsi, 4)
+    movl %edx, MIRROR_OBJECT_ARRAY_DATA_OFFSET(%edi, %esi, 4)
+//  movq %rdx, MIRROR_OBJECT_ARRAY_DATA_OFFSET(%rdi, %rsi, 4)
     movq %gs:THREAD_CARD_TABLE_OFFSET, %rdx
     shrl LITERAL(7), %edi
 //  shrl LITERAL(7), %rdi
@@ -1052,12 +1080,10 @@
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // Save all registers as basis for long jump context.
 
     // Outgoing argument set up.
-    movq %rsp, %rcx                         // Pass arg 4 = SP.
     movq %rdx, %rsi                         // Pass arg 2 = value.
-    movq %gs:THREAD_SELF_OFFSET, %rdx // Pass arg 3 = Thread::Current().
+    movq %gs:THREAD_SELF_OFFSET, %rdx       // Pass arg 3 = Thread::Current().
                                             // Pass arg 1 = array.
-
-    call SYMBOL(artThrowArrayStoreException) // (array, value, Thread*, SP)
+    call SYMBOL(artThrowArrayStoreException) // (array, value, Thread*)
     int3                          // unreached
 END_FUNCTION art_quick_aput_obj
 
@@ -1079,7 +1105,7 @@
 THREE_ARG_REF_DOWNCALL art_quick_set8_instance, artSet8InstanceFromCode, RETURN_IF_EAX_ZERO
 THREE_ARG_REF_DOWNCALL art_quick_set16_instance, artSet16InstanceFromCode, RETURN_IF_EAX_ZERO
 THREE_ARG_REF_DOWNCALL art_quick_set32_instance, artSet32InstanceFromCode, RETURN_IF_EAX_ZERO
-THREE_ARG_DOWNCALL art_quick_set64_instance, artSet64InstanceFromCode, RETURN_IF_EAX_ZERO
+THREE_ARG_REF_DOWNCALL art_quick_set64_instance, artSet64InstanceFromCode, RETURN_IF_EAX_ZERO
 THREE_ARG_REF_DOWNCALL art_quick_set_obj_instance, artSetObjInstanceFromCode, RETURN_IF_EAX_ZERO
 
 TWO_ARG_REF_DOWNCALL art_quick_get_byte_instance, artGetByteInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION
@@ -1105,55 +1131,25 @@
 
 // This is singled out as the argument order is different.
 DEFINE_FUNCTION art_quick_set64_static
-    movq %rsi, %rdx                    // pass new_val
-    movl 8(%rsp), %esi                 // pass referrer
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
-                                       // field_idx is in rdi
-    movq %gs:THREAD_SELF_OFFSET, %rcx  // pass Thread::Current()
-    movq %rsp, %r8                     // pass SP
-    call SYMBOL(artSet64StaticFromCode)  // (field_idx, referrer, new_val, Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
-    RETURN_IF_EAX_ZERO                 // return or deliver exception
+    movq %rsi, %rdx                      // pass new_val
+    movl 8(%rsp), %esi                   // pass referrer
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME
+                                         // field_idx is in rdi
+    movq %gs:THREAD_SELF_OFFSET, %rcx    // pass Thread::Current()
+    call SYMBOL(artSet64StaticFromCode)  // (field_idx, referrer, new_val, Thread*)
+    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
+    RETURN_IF_EAX_ZERO                   // return or deliver exception
 END_FUNCTION art_quick_set64_static
 
 
 DEFINE_FUNCTION art_quick_proxy_invoke_handler
-    // Save callee and GPR args, mixed together to agree with core spills bitmap of ref. and args
-    // callee save frame.
-    PUSH r15  // Callee save.
-    PUSH r14  // Callee save.
-    PUSH r13  // Callee save.
-    PUSH r12  // Callee save.
-    PUSH r9   // Quick arg 5.
-    PUSH r8   // Quick arg 4.
-    PUSH rsi  // Quick arg 1.
-    PUSH rbp  // Callee save.
-    PUSH rbx  // Callee save.
-    PUSH rdx  // Quick arg 2.
-    PUSH rcx  // Quick arg 3.
-    // Create space for FPR args and create 2 slots, 1 of padding and 1 for the ArtMethod*.
-    subq LITERAL(80 + 4*8), %rsp
-    CFI_ADJUST_CFA_OFFSET(80 + 4*8)
-    // Save FPRs.
-    movq %xmm0, 16(%rsp)
-    movq %xmm1, 24(%rsp)
-    movq %xmm2, 32(%rsp)
-    movq %xmm3, 40(%rsp)
-    movq %xmm4, 48(%rsp)
-    movq %xmm5, 56(%rsp)
-    movq %xmm6, 64(%rsp)
-    movq %xmm7, 72(%rsp)
-    movq %xmm12, 80(%rsp)
-    movq %xmm13, 88(%rsp)
-    movq %xmm14, 96(%rsp)
-    movq %xmm15, 104(%rsp)
-    // Store proxy method to bottom of stack.
-    movq %rdi, 0(%rsp)
-    movq %gs:THREAD_SELF_OFFSET, %rdx  // Pass Thread::Current().
-    movq %rsp, %rcx                    // Pass SP.
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_RDI
+
+    movq %gs:THREAD_SELF_OFFSET, %rdx       // Pass Thread::Current().
+    movq %rsp, %rcx                         // Pass SP.
     call SYMBOL(artQuickProxyInvokeHandler) // (proxy method, receiver, Thread*, SP)
-    movq %rax, %xmm0                   // Copy return value in case of float returns.
-    addq LITERAL(168 + 4*8), %rsp            // Pop arguments.
+    movq %rax, %xmm0                        // Copy return value in case of float returns.
+    addq LITERAL(168 + 4*8), %rsp           // Pop arguments.
     CFI_ADJUST_CFA_OFFSET(-168 - 4*8)
     RETURN_OR_DELIVER_PENDING_EXCEPTION
 END_FUNCTION art_quick_proxy_invoke_handler
@@ -1168,20 +1164,20 @@
     int3
 #else
     movl 8(%rsp), %edi            // load caller Method*
-    movl METHOD_DEX_CACHE_METHODS_OFFSET(%rdi), %edi  // load dex_cache_resolved_methods
-    movl OBJECT_ARRAY_DATA_OFFSET(%rdi, %rax, 4), %edi  // load the target method
+    movl MIRROR_ART_METHOD_DEX_CACHE_METHODS_OFFSET(%rdi), %edi  // load dex_cache_resolved_methods
+    movl MIRROR_OBJECT_ARRAY_DATA_OFFSET(%rdi, %rax, 4), %edi  // load the target method
     jmp art_quick_invoke_interface_trampoline
 #endif  // __APPLE__
 END_FUNCTION art_quick_imt_conflict_trampoline
 
 DEFINE_FUNCTION art_quick_resolution_trampoline
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     movq %gs:THREAD_SELF_OFFSET, %rdx
     movq %rsp, %rcx
     call SYMBOL(artQuickResolutionTrampoline) // (called, receiver, Thread*, SP)
     movq %rax, %r10               // Remember returned code pointer in R10.
     movq (%rsp), %rdi             // Load called method into RDI.
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     testq %r10, %r10              // If code pointer is NULL goto deliver pending exception.
     jz 1f
     jmp *%r10                     // Tail call into method.
@@ -1266,38 +1262,12 @@
     /*
      * Called to do a generic JNI down-call
      */
-DEFINE_FUNCTION_NO_HIDE art_quick_generic_jni_trampoline
-    // Save callee and GPR args, mixed together to agree with core spills bitmap.
-    PUSH r15  // Callee save.
-    PUSH r14  // Callee save.
-    PUSH r13  // Callee save.
-    PUSH r12  // Callee save.
-    PUSH r9   // Quick arg 5.
-    PUSH r8   // Quick arg 4.
-    PUSH rsi  // Quick arg 1.
-    PUSH rbp  // Callee save.
-    PUSH rbx  // Callee save.
-    PUSH rdx  // Quick arg 2.
-    PUSH rcx  // Quick arg 3.
-    // Create space for FPR args and create 2 slots, 1 of padding and 1 for the ArtMethod*.
-    subq LITERAL(80 + 4*8), %rsp
-    CFI_ADJUST_CFA_OFFSET(80 + 4*8)
-    // Save FPRs.
-    movq %xmm0, 16(%rsp)
-    movq %xmm1, 24(%rsp)
-    movq %xmm2, 32(%rsp)
-    movq %xmm3, 40(%rsp)
-    movq %xmm4, 48(%rsp)
-    movq %xmm5, 56(%rsp)
-    movq %xmm6, 64(%rsp)
-    movq %xmm7, 72(%rsp)
-    movq %xmm12, 80(%rsp)
-    movq %xmm13, 88(%rsp)
-    movq %xmm14, 96(%rsp)
-    movq %xmm15, 104(%rsp)
-    movq %rdi, 0(%rsp)              // Store native ArtMethod* to bottom of stack.
+DEFINE_FUNCTION art_quick_generic_jni_trampoline
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_RDI
+
     movq %rsp, %rbp                 // save SP at (old) callee-save frame
     CFI_DEF_CFA_REGISTER(rbp)
+
     //
     // reserve a lot of space
     //
@@ -1453,12 +1423,12 @@
      * RDI = method being called / to bridge to.
      * RSI, RDX, RCX, R8, R9 are arguments to that method.
      */
-DEFINE_FUNCTION_NO_HIDE art_quick_to_interpreter_bridge
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME   // Set up frame and save arguments.
+DEFINE_FUNCTION art_quick_to_interpreter_bridge
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME   // Set up frame and save arguments.
     movq %gs:THREAD_SELF_OFFSET, %rsi      // RSI := Thread::Current()
     movq %rsp, %rdx                        // RDX := sp
     call SYMBOL(artQuickToInterpreterBridge)  // (method, Thread*, SP)
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME  // TODO: no need to restore arguments in this case.
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME  // TODO: no need to restore arguments in this case.
     movq %rax, %xmm0                   // Place return value also into floating point return value.
     RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
 END_FUNCTION art_quick_to_interpreter_bridge
@@ -1471,15 +1441,14 @@
     int3
     int3
 #else
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
 
     movq %rdi, %r12               // Preserve method pointer in a callee-save.
 
     movq %gs:THREAD_SELF_OFFSET, %rdx   // Pass thread.
-    movq %rsp, %rcx                     // Pass SP.
     movq FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE-8(%rsp), %r8   // Pass return PC.
 
-    call SYMBOL(artInstrumentationMethodEntryFromCode) // (Method*, Object*, Thread*, SP, LR)
+    call SYMBOL(artInstrumentationMethodEntryFromCode) // (Method*, Object*, Thread*, LR)
 
                                   // %rax = result of call.
     movq %r12, %rdi               // Reload method pointer.
@@ -1487,7 +1456,7 @@
     leaq art_quick_instrumentation_exit(%rip), %r12   // Set up return through instrumentation
     movq %r12, FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE-8(%rsp) // exit.
 
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
 
     jmp *%rax                     // Tail call to intended method.
 #endif  // __APPLE__
@@ -1496,7 +1465,7 @@
 DEFINE_FUNCTION art_quick_instrumentation_exit
     pushq LITERAL(0)          // Push a fake return PC as there will be none on the stack.
 
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME
 
     // We need to save rax and xmm0. We could use a callee-save from SETUP_REF_ONLY, but then
     // we would need to fully restore it. As there are a good number of callee-save registers, it
@@ -1536,9 +1505,8 @@
     pushq %rsi                     // Fake that we were called. Use hidden arg.
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
                                    // Stack should be aligned now.
-    movq %rsp, %rsi                           // Pass SP.
     movq %gs:THREAD_SELF_OFFSET, %rdi         // Pass Thread.
-    call SYMBOL(artDeoptimize) // artDeoptimize(Thread*, SP)
+    call SYMBOL(artDeoptimize) // artDeoptimize(Thread*)
     int3                           // Unreachable.
 END_FUNCTION art_quick_deoptimize
 
@@ -1551,15 +1519,15 @@
      *    rsi:   comp string object (known non-null)
      */
 DEFINE_FUNCTION art_quick_string_compareto
-    movl STRING_COUNT_OFFSET(%edi), %r8d
-    movl STRING_COUNT_OFFSET(%esi), %r9d
-    movl STRING_VALUE_OFFSET(%edi), %r10d
-    movl STRING_VALUE_OFFSET(%esi), %r11d
-    movl STRING_OFFSET_OFFSET(%edi), %eax
-    movl STRING_OFFSET_OFFSET(%esi), %ecx
+    movl MIRROR_STRING_COUNT_OFFSET(%edi), %r8d
+    movl MIRROR_STRING_COUNT_OFFSET(%esi), %r9d
+    movl MIRROR_STRING_VALUE_OFFSET(%edi), %r10d
+    movl MIRROR_STRING_VALUE_OFFSET(%esi), %r11d
+    movl MIRROR_STRING_OFFSET_OFFSET(%edi), %eax
+    movl MIRROR_STRING_OFFSET_OFFSET(%esi), %ecx
     /* Build pointers to the start of string data */
-    leal STRING_DATA_OFFSET(%r10d, %eax, 2), %esi
-    leal STRING_DATA_OFFSET(%r11d, %ecx, 2), %edi
+    leal MIRROR_CHAR_ARRAY_DATA_OFFSET(%r10d, %eax, 2), %esi
+    leal MIRROR_CHAR_ARRAY_DATA_OFFSET(%r11d, %ecx, 2), %edi
     /* Calculate min length and count diff */
     movl  %r8d, %ecx
     movl  %r8d, %eax
@@ -1605,5 +1573,3 @@
     call PLT_SYMBOL(longjmp)
     int3                            // won't get here
 END_FUNCTION art_nested_signal_return
-
-
diff --git a/runtime/arch/x86_64/thread_x86_64.cc b/runtime/arch/x86_64/thread_x86_64.cc
index 6dff2b4..553b656 100644
--- a/runtime/arch/x86_64/thread_x86_64.cc
+++ b/runtime/arch/x86_64/thread_x86_64.cc
@@ -49,29 +49,16 @@
 
   // Sanity check that reads from %gs point to this Thread*.
   Thread* self_check;
-  CHECK_EQ(THREAD_SELF_OFFSET, SelfOffset<8>().Int32Value());
   __asm__ __volatile__("movq %%gs:(%1), %0"
       : "=r"(self_check)  // output
       : "r"(THREAD_SELF_OFFSET)  // input
       :);  // clobber
   CHECK_EQ(self_check, this);
-
-  // Sanity check other offsets.
-  CHECK_EQ(static_cast<size_t>(RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET),
-           Runtime::GetCalleeSaveMethodOffset(Runtime::kSaveAll));
-  CHECK_EQ(static_cast<size_t>(RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET),
-           Runtime::GetCalleeSaveMethodOffset(Runtime::kRefsOnly));
-  CHECK_EQ(static_cast<size_t>(RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET),
-           Runtime::GetCalleeSaveMethodOffset(Runtime::kRefsAndArgs));
-  CHECK_EQ(THREAD_EXCEPTION_OFFSET, ExceptionOffset<8>().Int32Value());
-  CHECK_EQ(THREAD_CARD_TABLE_OFFSET, CardTableOffset<8>().Int32Value());
-  CHECK_EQ(THREAD_ID_OFFSET, ThinLockIdOffset<8>().Int32Value());
 }
 
 void Thread::CleanupCpu() {
   // Sanity check that reads from %gs point to this Thread*.
   Thread* self_check;
-  CHECK_EQ(THREAD_SELF_OFFSET, SelfOffset<8>().Int32Value());
   __asm__ __volatile__("movq %%gs:(%1), %0"
       : "=r"(self_check)  // output
       : "r"(THREAD_SELF_OFFSET)  // input
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index 62f3593..26df045 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -17,56 +17,147 @@
 #ifndef ART_RUNTIME_ASM_SUPPORT_H_
 #define ART_RUNTIME_ASM_SUPPORT_H_
 
+#if defined(__cplusplus)
+#include "mirror/art_method.h"
+#include "mirror/class.h"
+#include "mirror/string.h"
+#include "runtime.h"
+#include "thread.h"
+#endif
+
 #include "read_barrier_c.h"
 
-// Value loaded into rSUSPEND for quick. When this value is counted down to zero we do a suspend
-// check.
-#define SUSPEND_CHECK_INTERVAL (1000)
+#if defined(__arm__) ||  defined(__aarch64__) || defined(__mips__)
+// In quick code for ARM, ARM64 and MIPS we make poor use of registers and perform frequent suspend
+// checks in the event of loop back edges. The SUSPEND_CHECK_INTERVAL constant is loaded into a
+// register at the point of an up-call or after handling a suspend check. It reduces the number of
+// loads of the TLS suspend check value by the given amount (turning it into a decrement and compare
+// of a register). This increases the time for a thread to respond to requests from GC and the
+// debugger, damaging GC performance and creating other unwanted artifacts. For example, this count
+// has the effect of making loops and Java code look cold in profilers, where the count is reset
+// impacts where samples will occur. Reducing the count as much as possible improves profiler
+// accuracy in tools like traceview.
+// TODO: get a compiler that can do a proper job of loop optimization and remove this.
+#define SUSPEND_CHECK_INTERVAL 1000
+#endif
+
+#if defined(__cplusplus)
+
+#ifndef ADD_TEST_EQ  // Allow #include-r to replace with their own.
+#define ADD_TEST_EQ(x, y) CHECK_EQ(x, y);
+#endif
+
+static inline void CheckAsmSupportOffsetsAndSizes() {
+#else
+#define ADD_TEST_EQ(x, y)
+#endif
+
+// Size of references to the heap on the stack.
+#define STACK_REFERENCE_SIZE 4
+ADD_TEST_EQ(static_cast<size_t>(STACK_REFERENCE_SIZE), sizeof(art::StackReference<art::mirror::Object>))
+
+// Note: these callee save methods loads require read barriers.
+// Offset of field Runtime::callee_save_methods_[kSaveAll]
+#define RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET 0
+ADD_TEST_EQ(static_cast<size_t>(RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET),
+            art::Runtime::GetCalleeSaveMethodOffset(art::Runtime::kSaveAll))
+
+// Offset of field Runtime::callee_save_methods_[kRefsOnly]
+#define RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET __SIZEOF_POINTER__
+ADD_TEST_EQ(static_cast<size_t>(RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET),
+            art::Runtime::GetCalleeSaveMethodOffset(art::Runtime::kRefsOnly))
+
+// Offset of field Runtime::callee_save_methods_[kRefsAndArgs]
+#define RUNTIME_REFS_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET (2 * __SIZEOF_POINTER__)
+ADD_TEST_EQ(static_cast<size_t>(RUNTIME_REFS_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET),
+            art::Runtime::GetCalleeSaveMethodOffset(art::Runtime::kRefsAndArgs))
+
+// Offset of field Thread::tls32_.state_and_flags.
+#define THREAD_FLAGS_OFFSET 0
+ADD_TEST_EQ(THREAD_FLAGS_OFFSET,
+            art::Thread::ThreadFlagsOffset<__SIZEOF_POINTER__>().Int32Value())
+
+// Offset of field Thread::tls32_.thin_lock_thread_id.
+#define THREAD_ID_OFFSET 12
+ADD_TEST_EQ(THREAD_ID_OFFSET,
+            art::Thread::ThinLockIdOffset<__SIZEOF_POINTER__>().Int32Value())
+
+// Offset of field Thread::tlsPtr_.card_table.
+#define THREAD_CARD_TABLE_OFFSET 120
+ADD_TEST_EQ(THREAD_CARD_TABLE_OFFSET,
+            art::Thread::CardTableOffset<__SIZEOF_POINTER__>().Int32Value())
+
+// Offset of field Thread::tlsPtr_.exception.
+#define THREAD_EXCEPTION_OFFSET (THREAD_CARD_TABLE_OFFSET + __SIZEOF_POINTER__)
+ADD_TEST_EQ(THREAD_EXCEPTION_OFFSET,
+            art::Thread::ExceptionOffset<__SIZEOF_POINTER__>().Int32Value())
+
+// Offset of field Thread::tlsPtr_.managed_stack.top_quick_frame_.
+#define THREAD_TOP_QUICK_FRAME_OFFSET (THREAD_CARD_TABLE_OFFSET + (3 * __SIZEOF_POINTER__))
+ADD_TEST_EQ(THREAD_TOP_QUICK_FRAME_OFFSET,
+            art::Thread::TopOfManagedStackOffset<__SIZEOF_POINTER__>().Int32Value())
+
+// Offset of field Thread::tlsPtr_.managed_stack.top_quick_frame_.
+#define THREAD_SELF_OFFSET (THREAD_CARD_TABLE_OFFSET + (8 * __SIZEOF_POINTER__))
+ADD_TEST_EQ(THREAD_SELF_OFFSET,
+            art::Thread::SelfOffset<__SIZEOF_POINTER__>().Int32Value())
 
 // Offsets within java.lang.Object.
-#define CLASS_OFFSET 0
-#define LOCK_WORD_OFFSET 4
+#define MIRROR_OBJECT_CLASS_OFFSET 0
+ADD_TEST_EQ(MIRROR_OBJECT_CLASS_OFFSET, art::mirror::Object::ClassOffset().Int32Value())
+#define MIRROR_OBJECT_LOCK_WORD_OFFSET 4
+ADD_TEST_EQ(MIRROR_OBJECT_LOCK_WORD_OFFSET, art::mirror::Object::MonitorOffset().Int32Value())
 
-#ifndef USE_BAKER_OR_BROOKS_READ_BARRIER
-
-// Offsets within java.lang.Class.
-#define CLASS_COMPONENT_TYPE_OFFSET 12
-
-// Array offsets.
-#define ARRAY_LENGTH_OFFSET 8
-#define OBJECT_ARRAY_DATA_OFFSET 12
-
-// Offsets within java.lang.String.
-#define STRING_VALUE_OFFSET 8
-#define STRING_COUNT_OFFSET 12
-#define STRING_OFFSET_OFFSET 20
-#define STRING_DATA_OFFSET 12
-
-// Offsets within java.lang.Method.
-#define METHOD_DEX_CACHE_METHODS_OFFSET 12
-#define METHOD_PORTABLE_CODE_OFFSET 40
-#define METHOD_QUICK_CODE_OFFSET 48
-
+#if defined(USE_BAKER_OR_BROOKS_READ_BARRIER)
+#define MIRROR_OBJECT_HEADER_SIZE 16
 #else
+#define MIRROR_OBJECT_HEADER_SIZE 8
+#endif
+ADD_TEST_EQ(size_t(MIRROR_OBJECT_HEADER_SIZE), sizeof(art::mirror::Object))
 
 // Offsets within java.lang.Class.
-#define CLASS_COMPONENT_TYPE_OFFSET 20
+#define MIRROR_CLASS_COMPONENT_TYPE_OFFSET (4 + MIRROR_OBJECT_HEADER_SIZE)
+ADD_TEST_EQ(MIRROR_CLASS_COMPONENT_TYPE_OFFSET,
+            art::mirror::Class::ComponentTypeOffset().Int32Value())
 
 // Array offsets.
-#define ARRAY_LENGTH_OFFSET 16
-#define OBJECT_ARRAY_DATA_OFFSET 20
+#define MIRROR_ARRAY_LENGTH_OFFSET      MIRROR_OBJECT_HEADER_SIZE
+ADD_TEST_EQ(MIRROR_ARRAY_LENGTH_OFFSET, art::mirror::Array::LengthOffset().Int32Value())
+
+#define MIRROR_CHAR_ARRAY_DATA_OFFSET   (4 + MIRROR_OBJECT_HEADER_SIZE)
+ADD_TEST_EQ(MIRROR_CHAR_ARRAY_DATA_OFFSET,
+            art::mirror::Array::DataOffset(sizeof(uint16_t)).Int32Value())
+
+#define MIRROR_OBJECT_ARRAY_DATA_OFFSET (4 + MIRROR_OBJECT_HEADER_SIZE)
+ADD_TEST_EQ(MIRROR_OBJECT_ARRAY_DATA_OFFSET,
+    art::mirror::Array::DataOffset(
+        sizeof(art::mirror::HeapReference<art::mirror::Object>)).Int32Value())
 
 // Offsets within java.lang.String.
-#define STRING_VALUE_OFFSET 16
-#define STRING_COUNT_OFFSET 20
-#define STRING_OFFSET_OFFSET 28
-#define STRING_DATA_OFFSET 20
+#define MIRROR_STRING_VALUE_OFFSET  MIRROR_OBJECT_HEADER_SIZE
+ADD_TEST_EQ(MIRROR_STRING_VALUE_OFFSET, art::mirror::String::ValueOffset().Int32Value())
 
-// Offsets within java.lang.Method.
-#define METHOD_DEX_CACHE_METHODS_OFFSET 20
-#define METHOD_PORTABLE_CODE_OFFSET 48
-#define METHOD_QUICK_CODE_OFFSET 56
+#define MIRROR_STRING_COUNT_OFFSET  (4 + MIRROR_OBJECT_HEADER_SIZE)
+ADD_TEST_EQ(MIRROR_STRING_COUNT_OFFSET, art::mirror::String::CountOffset().Int32Value())
 
+#define MIRROR_STRING_OFFSET_OFFSET (12 + MIRROR_OBJECT_HEADER_SIZE)
+ADD_TEST_EQ(MIRROR_STRING_OFFSET_OFFSET, art::mirror::String::OffsetOffset().Int32Value())
+
+// Offsets within java.lang.reflect.ArtMethod.
+#define MIRROR_ART_METHOD_DEX_CACHE_METHODS_OFFSET (4 + MIRROR_OBJECT_HEADER_SIZE)
+ADD_TEST_EQ(MIRROR_ART_METHOD_DEX_CACHE_METHODS_OFFSET,
+            art::mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value())
+
+#define MIRROR_ART_METHOD_PORTABLE_CODE_OFFSET     (32 + MIRROR_OBJECT_HEADER_SIZE)
+ADD_TEST_EQ(MIRROR_ART_METHOD_PORTABLE_CODE_OFFSET,
+            art::mirror::ArtMethod::EntryPointFromPortableCompiledCodeOffset().Int32Value())
+
+#define MIRROR_ART_METHOD_QUICK_CODE_OFFSET        (40 + MIRROR_OBJECT_HEADER_SIZE)
+ADD_TEST_EQ(MIRROR_ART_METHOD_QUICK_CODE_OFFSET,
+            art::mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value())
+
+#if defined(__cplusplus)
+}  // End of CheckAsmSupportOffsets.
 #endif
 
 #endif  // ART_RUNTIME_ASM_SUPPORT_H_
diff --git a/runtime/base/allocator.cc b/runtime/base/allocator.cc
index f67616e..994e235 100644
--- a/runtime/base/allocator.cc
+++ b/runtime/base/allocator.cc
@@ -74,6 +74,7 @@
 
 namespace TrackedAllocators {
 
+// These globals are safe since they don't have any non-trivial destructors.
 Atomic<size_t> g_bytes_used[kAllocatorTagCount];
 volatile size_t g_max_bytes_used[kAllocatorTagCount];
 Atomic<uint64_t> g_total_bytes_used[kAllocatorTagCount];
diff --git a/runtime/base/bit_vector.cc b/runtime/base/bit_vector.cc
index 3d2f0de..5b8b6e2 100644
--- a/runtime/base/bit_vector.cc
+++ b/runtime/base/bit_vector.cc
@@ -16,6 +16,8 @@
 
 #include "bit_vector.h"
 
+#include <sstream>
+
 #include "allocator.h"
 #include "bit_vector-inl.h"
 
@@ -145,10 +147,7 @@
 
   // Is the storage size smaller than src's?
   if (storage_size_ < union_with_size) {
-    changed = true;
-
-    // Set it to reallocate.
-    SetBit(highest_bit);
+    EnsureSize(highest_bit);
 
     // Paranoid: storage size should be big enough to hold this bit now.
     DCHECK_LT(static_cast<uint32_t> (highest_bit), storage_size_ * kWordBits);
diff --git a/runtime/base/bit_vector_test.cc b/runtime/base/bit_vector_test.cc
index df5d79d..31fd0e7 100644
--- a/runtime/base/bit_vector_test.cc
+++ b/runtime/base/bit_vector_test.cc
@@ -141,4 +141,30 @@
   EXPECT_EQ(64u, bv.NumSetBits());
 }
 
+TEST(BitVector, UnionIfNotIn) {
+  {
+    BitVector first(2, true, Allocator::GetMallocAllocator());
+    BitVector second(5, true, Allocator::GetMallocAllocator());
+    BitVector third(5, true, Allocator::GetMallocAllocator());
+
+    second.SetBit(64);
+    third.SetBit(64);
+    bool changed = first.UnionIfNotIn(&second, &third);
+    EXPECT_EQ(0u, first.NumSetBits());
+    EXPECT_FALSE(changed);
+  }
+
+  {
+    BitVector first(2, true, Allocator::GetMallocAllocator());
+    BitVector second(5, true, Allocator::GetMallocAllocator());
+    BitVector third(5, true, Allocator::GetMallocAllocator());
+
+    second.SetBit(64);
+    bool changed = first.UnionIfNotIn(&second, &third);
+    EXPECT_EQ(1u, first.NumSetBits());
+    EXPECT_TRUE(changed);
+    EXPECT_TRUE(first.IsBitSet(64));
+  }
+}
+
 }  // namespace art
diff --git a/runtime/base/casts.h b/runtime/base/casts.h
index be94c2e..138c2fd 100644
--- a/runtime/base/casts.h
+++ b/runtime/base/casts.h
@@ -19,6 +19,8 @@
 
 #include <assert.h>
 #include <string.h>
+#include <type_traits>
+
 #include "base/macros.h"
 
 namespace art {
@@ -65,16 +67,9 @@
 
 template<typename To, typename From>     // use like this: down_cast<T*>(foo);
 inline To down_cast(From* f) {                   // so we only accept pointers
-  // Ensures that To is a sub-type of From *.  This test is here only
-  // for compile-time type checking, and has no overhead in an
-  // optimized build at run-time, as it will be optimized away
-  // completely.
-  if (false) {
-    implicit_cast<From*, To>(0);
-  }
+  static_assert(std::is_base_of<From, typename std::remove_pointer<To>::type>::value,
+                "down_cast unsafe as To is not a subtype of From");
 
-  //
-  // assert(f == NULL || dynamic_cast<To>(f) != NULL);  // RTTI: debug mode only!
   return static_cast<To>(f);
 }
 
diff --git a/runtime/base/dumpable.h b/runtime/base/dumpable.h
new file mode 100644
index 0000000..3c316cc
--- /dev/null
+++ b/runtime/base/dumpable.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#ifndef ART_RUNTIME_BASE_DUMPABLE_H_
+#define ART_RUNTIME_BASE_DUMPABLE_H_
+
+#include "base/macros.h"
+
+namespace art {
+
+// A convenience to allow any class with a "Dump(std::ostream& os)" member function
+// but without an operator<< to be used as if it had an operator<<. Use like this:
+//
+//   os << Dumpable<MyType>(my_type_instance);
+//
+template<typename T>
+class Dumpable FINAL {
+ public:
+  explicit Dumpable(const T& value) : value_(value) {
+  }
+
+  void Dump(std::ostream& os) const {
+    value_.Dump(os);
+  }
+
+ private:
+  const T& value_;
+
+  DISALLOW_COPY_AND_ASSIGN(Dumpable);
+};
+
+template<typename T>
+std::ostream& operator<<(std::ostream& os, const Dumpable<T>& rhs) {
+  rhs.Dump(os);
+  return os;
+}
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_BASE_DUMPABLE_H_
diff --git a/runtime/base/logging.cc b/runtime/base/logging.cc
index b2ad1d0..46c3538 100644
--- a/runtime/base/logging.cc
+++ b/runtime/base/logging.cc
@@ -16,17 +16,25 @@
 
 #include "logging.h"
 
+#include <sstream>
+
 #include "base/mutex.h"
 #include "runtime.h"
 #include "thread-inl.h"
 #include "utils.h"
 
+// Headers for LogMessage::LogLine.
+#ifdef HAVE_ANDROID_OS
+#include "cutils/log.h"
+#else
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
 namespace art {
 
 LogVerbosity gLogVerbosity;
 
-std::vector<std::string> gVerboseMethods;
-
 unsigned int gAborting = 0;
 
 static LogSeverity gMinimumLogSeverity = INFO;
@@ -47,14 +55,6 @@
                                                         : "art";
 }
 
-// Configure logging based on ANDROID_LOG_TAGS environment variable.
-// We need to parse a string that looks like
-//
-//      *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i
-//
-// The tag (or '*' for the global level) comes first, followed by a colon
-// and a letter indicating the minimum priority level we're expected to log.
-// This can be used to reveal or conceal logs with specific tags.
 void InitLogging(char* argv[]) {
   if (gCmdLine.get() != nullptr) {
     return;
@@ -65,27 +65,27 @@
   // Stash the command line for later use. We can use /proc/self/cmdline on Linux to recover this,
   // but we don't have that luxury on the Mac, and there are a couple of argv[0] variants that are
   // commonly used.
-  if (argv != NULL) {
+  if (argv != nullptr) {
     gCmdLine.reset(new std::string(argv[0]));
-    for (size_t i = 1; argv[i] != NULL; ++i) {
+    for (size_t i = 1; argv[i] != nullptr; ++i) {
       gCmdLine->append(" ");
       gCmdLine->append(argv[i]);
     }
     gProgramInvocationName.reset(new std::string(argv[0]));
     const char* last_slash = strrchr(argv[0], '/');
-    gProgramInvocationShortName.reset(new std::string((last_slash != NULL) ? last_slash + 1
+    gProgramInvocationShortName.reset(new std::string((last_slash != nullptr) ? last_slash + 1
                                                                            : argv[0]));
   } else {
-    // TODO: fall back to /proc/self/cmdline when argv is NULL on Linux
+    // TODO: fall back to /proc/self/cmdline when argv is NULL on Linux.
     gCmdLine.reset(new std::string("<unset>"));
   }
   const char* tags = getenv("ANDROID_LOG_TAGS");
-  if (tags == NULL) {
+  if (tags == nullptr) {
     return;
   }
 
   std::vector<std::string> specs;
-  Split(tags, ' ', specs);
+  Split(tags, ' ', &specs);
   for (size_t i = 0; i < specs.size(); ++i) {
     // "tag-pattern:[vdiwefs]"
     std::string spec(specs[i]);
@@ -119,47 +119,121 @@
   }
 }
 
-LogMessageData::LogMessageData(const char* file, int line, LogSeverity severity, int error)
-    : file(file),
-      line_number(line),
-      severity(severity),
-      error(error) {
-  const char* last_slash = strrchr(file, '/');
-  file = (last_slash == NULL) ? file : last_slash + 1;
-}
+// This indirection greatly reduces the stack impact of having
+// lots of checks/logging in a function.
+class LogMessageData {
+ public:
+  LogMessageData(const char* file, unsigned int line, LogSeverity severity, int error)
+      : file_(file),
+        line_number_(line),
+        severity_(severity),
+        error_(error) {
+    const char* last_slash = strrchr(file, '/');
+    file = (last_slash == nullptr) ? file : last_slash + 1;
+  }
 
+  const char * GetFile() const {
+    return file_;
+  }
+
+  unsigned int GetLineNumber() const {
+    return line_number_;
+  }
+
+  LogSeverity GetSeverity() const {
+    return severity_;
+  }
+
+  int GetError() const {
+    return error_;
+  }
+
+  std::ostream& GetBuffer() {
+    return buffer_;
+  }
+
+  std::string ToString() const {
+    return buffer_.str();
+  }
+
+ private:
+  std::ostringstream buffer_;
+  const char* const file_;
+  const unsigned int line_number_;
+  const LogSeverity severity_;
+  const int error_;
+
+  DISALLOW_COPY_AND_ASSIGN(LogMessageData);
+};
+
+
+LogMessage::LogMessage(const char* file, unsigned int line, LogSeverity severity, int error)
+  : data_(new LogMessageData(file, line, severity, error)) {
+}
 LogMessage::~LogMessage() {
-  if (data_->severity < gMinimumLogSeverity) {
+  if (data_->GetSeverity() < gMinimumLogSeverity) {
     return;  // No need to format something we're not going to output.
   }
 
   // Finish constructing the message.
-  if (data_->error != -1) {
-    data_->buffer << ": " << strerror(data_->error);
+  if (data_->GetError() != -1) {
+    data_->GetBuffer() << ": " << strerror(data_->GetError());
   }
-  std::string msg(data_->buffer.str());
+  std::string msg(data_->ToString());
 
   // Do the actual logging with the lock held.
   {
     MutexLock mu(Thread::Current(), *Locks::logging_lock_);
     if (msg.find('\n') == std::string::npos) {
-      LogLine(*data_, msg.c_str());
+      LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), msg.c_str());
     } else {
       msg += '\n';
       size_t i = 0;
       while (i < msg.size()) {
         size_t nl = msg.find('\n', i);
         msg[nl] = '\0';
-        LogLine(*data_, &msg[i]);
+        LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), &msg[i]);
         i = nl + 1;
       }
     }
   }
 
   // Abort if necessary.
-  if (data_->severity == FATAL) {
+  if (data_->GetSeverity() == FATAL) {
     Runtime::Abort();
   }
 }
 
+std::ostream& LogMessage::stream() {
+  return data_->GetBuffer();
+}
+
+#ifdef HAVE_ANDROID_OS
+static const android_LogPriority kLogSeverityToAndroidLogPriority[] = {
+  ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN,
+  ANDROID_LOG_ERROR, ANDROID_LOG_FATAL, ANDROID_LOG_FATAL
+};
+COMPILE_ASSERT(arraysize(kLogSeverityToAndroidLogPriority) == INTERNAL_FATAL + 1,
+               mismatch_in_size_of_kLogSeverityToAndroidLogPriority_and_values_in_LogSeverity);
+#endif
+
+void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity log_severity,
+                         const char* message) {
+#ifdef HAVE_ANDROID_OS
+  const char* tag = ProgramInvocationShortName();
+  int priority = kLogSeverityToAndroidLogPriority[log_severity];
+  if (priority == ANDROID_LOG_FATAL) {
+    LOG_PRI(priority, tag, "%s:%u] %s", file, line, message);
+  } else {
+    LOG_PRI(priority, tag, "%s", message);
+  }
+#else
+  static const char* log_characters = "VDIWEFF";
+  CHECK_EQ(strlen(log_characters), INTERNAL_FATAL + 1U);
+  char severity = log_characters[log_severity];
+  fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n",
+          ProgramInvocationShortName(), severity, getpid(), ::art::GetTid(), file, line, message);
+#endif
+}
+
 }  // namespace art
diff --git a/runtime/base/logging.h b/runtime/base/logging.h
index cf3e763..baa83e3 100644
--- a/runtime/base/logging.h
+++ b/runtime/base/logging.h
@@ -17,29 +17,113 @@
 #ifndef ART_RUNTIME_BASE_LOGGING_H_
 #define ART_RUNTIME_BASE_LOGGING_H_
 
-#include <cerrno>
-#include <cstring>
-#include <iostream>  // NOLINT
 #include <memory>
-#include <sstream>
-#include <signal.h>
-#include <vector>
+#include <ostream>
 
 #include "base/macros.h"
-#include "log_severity.h"
 
+namespace art {
+
+enum LogSeverity {
+  VERBOSE,
+  DEBUG,
+  INFO,
+  WARNING,
+  ERROR,
+  FATAL,
+  INTERNAL_FATAL,  // For Runtime::Abort.
+};
+
+// The members of this struct are the valid arguments to VLOG and VLOG_IS_ON in code,
+// and the "-verbose:" command line argument.
+struct LogVerbosity {
+  bool class_linker;  // Enabled with "-verbose:class".
+  bool compiler;
+  bool gc;
+  bool heap;
+  bool jdwp;
+  bool jni;
+  bool monitor;
+  bool profiler;
+  bool signals;
+  bool startup;
+  bool third_party_jni;  // Enabled with "-verbose:third-party-jni".
+  bool threads;
+  bool verifier;
+};
+
+// Global log verbosity setting, initialized by InitLogging.
+extern LogVerbosity gLogVerbosity;
+
+// 0 if not abort, non-zero if an abort is in progress. Used on fatal exit to prevents recursive
+// aborts. Global declaration allows us to disable some error checking to ensure fatal shutdown
+// makes forward progress.
+extern unsigned int gAborting;
+
+// Configure logging based on ANDROID_LOG_TAGS environment variable.
+// We need to parse a string that looks like
+//
+//      *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i
+//
+// The tag (or '*' for the global level) comes first, followed by a colon
+// and a letter indicating the minimum priority level we're expected to log.
+// This can be used to reveal or conceal logs with specific tags.
+extern void InitLogging(char* argv[]);
+
+// Returns the command line used to invoke the current tool or nullptr if InitLogging hasn't been
+// performed.
+extern const char* GetCmdLine();
+
+// The command used to start the ART runtime, such as "/system/bin/dalvikvm". If InitLogging hasn't
+// been performed then just returns "art"
+extern const char* ProgramInvocationName();
+
+// A short version of the command used to start the ART runtime, such as "dalvikvm". If InitLogging
+// hasn't been performed then just returns "art"
+extern const char* ProgramInvocationShortName();
+
+// Logs a message to logcat on Android otherwise to stderr. If the severity is FATAL it also causes
+// an abort. For example: LOG(FATAL) << "We didn't expect to reach here";
+#define LOG(severity) ::art::LogMessage(__FILE__, __LINE__, severity, -1).stream()
+
+// A variant of LOG that also logs the current errno value. To be used when library calls fail.
+#define PLOG(severity) ::art::LogMessage(__FILE__, __LINE__, severity, errno).stream()
+
+// Marker that code is yet to be implemented.
+#define UNIMPLEMENTED(level) LOG(level) << __PRETTY_FUNCTION__ << " unimplemented "
+
+// Is verbose logging enabled for the given module? Where the module is defined in LogVerbosity.
+#define VLOG_IS_ON(module) UNLIKELY(::art::gLogVerbosity.module)
+
+// Variant of LOG that logs when verbose logging is enabled for a module. For example,
+// VLOG(jni) << "A JNI operation was performed";
+#define VLOG(module) \
+  if (VLOG_IS_ON(module)) \
+    ::art::LogMessage(__FILE__, __LINE__, INFO, -1).stream()
+
+// Return the stream associated with logging for the given module.
+#define VLOG_STREAM(module) ::art::LogMessage(__FILE__, __LINE__, INFO, -1).stream()
+
+// Check whether condition x holds and LOG(FATAL) if not. The value of the expression x is only
+// evaluated once. Extra logging can be appended using << after. For example,
+// CHECK(false == true) results in a log message of "Check failed: false == true".
 #define CHECK(x) \
   if (UNLIKELY(!(x))) \
-    ::art::LogMessage(__FILE__, __LINE__, FATAL, -1).stream() \
+    ::art::LogMessage(__FILE__, __LINE__, ::art::FATAL, -1).stream() \
         << "Check failed: " #x << " "
 
+// Helper for CHECK_xx(x,y) macros.
 #define CHECK_OP(LHS, RHS, OP) \
   for (auto _values = ::art::MakeEagerEvaluator(LHS, RHS); \
        UNLIKELY(!(_values.lhs OP _values.rhs)); /* empty */) \
-    ::art::LogMessage(__FILE__, __LINE__, FATAL, -1).stream() \
+    ::art::LogMessage(__FILE__, __LINE__, ::art::FATAL, -1).stream() \
         << "Check failed: " << #LHS << " " << #OP << " " << #RHS \
         << " (" #LHS "=" << _values.lhs << ", " #RHS "=" << _values.rhs << ") "
 
+
+// Check whether a condition holds between x and y, LOG(FATAL) if not. The value of the expressions
+// x and y is evaluated once. Extra logging can be appended using << after. For example,
+// CHECK_NE(0 == 1, false) results in "Check failed: false != false (0==1=false, false=false) ".
 #define CHECK_EQ(x, y) CHECK_OP(x, y, ==)
 #define CHECK_NE(x, y) CHECK_OP(x, y, !=)
 #define CHECK_LE(x, y) CHECK_OP(x, y, <=)
@@ -47,22 +131,25 @@
 #define CHECK_GE(x, y) CHECK_OP(x, y, >=)
 #define CHECK_GT(x, y) CHECK_OP(x, y, >)
 
+// Helper for CHECK_STRxx(s1,s2) macros.
 #define CHECK_STROP(s1, s2, sense) \
   if (UNLIKELY((strcmp(s1, s2) == 0) != sense)) \
-    LOG(FATAL) << "Check failed: " \
-               << "\"" << s1 << "\"" \
-               << (sense ? " == " : " != ") \
-               << "\"" << s2 << "\""
+    LOG(::art::FATAL) << "Check failed: " \
+        << "\"" << s1 << "\"" \
+        << (sense ? " == " : " != ") \
+        << "\"" << s2 << "\""
 
+// Check for string (const char*) equality between s1 and s2, LOG(FATAL) if not.
 #define CHECK_STREQ(s1, s2) CHECK_STROP(s1, s2, true)
 #define CHECK_STRNE(s1, s2) CHECK_STROP(s1, s2, false)
 
+// Perform the pthread function call(args), LOG(FATAL) on error.
 #define CHECK_PTHREAD_CALL(call, args, what) \
   do { \
     int rc = call args; \
     if (rc != 0) { \
       errno = rc; \
-      PLOG(FATAL) << # call << " failed for " << what; \
+      PLOG(::art::FATAL) << # call << " failed for " << what; \
     } \
   } while (false)
 
@@ -74,81 +161,34 @@
 //          n / 2;
 //    }
 #define CHECK_CONSTEXPR(x, out, dummy) \
-  (UNLIKELY(!(x))) ? (LOG(FATAL) << "Check failed: " << #x out, dummy) :
+  (UNLIKELY(!(x))) ? (LOG(::art::FATAL) << "Check failed: " << #x out, dummy) :
 
-#ifndef NDEBUG
 
-#define DCHECK(x) CHECK(x)
-#define DCHECK_EQ(x, y) CHECK_EQ(x, y)
-#define DCHECK_NE(x, y) CHECK_NE(x, y)
-#define DCHECK_LE(x, y) CHECK_LE(x, y)
-#define DCHECK_LT(x, y) CHECK_LT(x, y)
-#define DCHECK_GE(x, y) CHECK_GE(x, y)
-#define DCHECK_GT(x, y) CHECK_GT(x, y)
-#define DCHECK_STREQ(s1, s2) CHECK_STREQ(s1, s2)
-#define DCHECK_STRNE(s1, s2) CHECK_STRNE(s1, s2)
-#define DCHECK_CONSTEXPR(x, out, dummy) CHECK_CONSTEXPR(x, out, dummy)
-
-#else  // NDEBUG
-
-#define DCHECK(condition) \
-  while (false) \
-    CHECK(condition)
-
-#define DCHECK_EQ(val1, val2) \
-  while (false) \
-    CHECK_EQ(val1, val2)
-
-#define DCHECK_NE(val1, val2) \
-  while (false) \
-    CHECK_NE(val1, val2)
-
-#define DCHECK_LE(val1, val2) \
-  while (false) \
-    CHECK_LE(val1, val2)
-
-#define DCHECK_LT(val1, val2) \
-  while (false) \
-    CHECK_LT(val1, val2)
-
-#define DCHECK_GE(val1, val2) \
-  while (false) \
-    CHECK_GE(val1, val2)
-
-#define DCHECK_GT(val1, val2) \
-  while (false) \
-    CHECK_GT(val1, val2)
-
-#define DCHECK_STREQ(str1, str2) \
-  while (false) \
-    CHECK_STREQ(str1, str2)
-
-#define DCHECK_STRNE(str1, str2) \
-  while (false) \
-    CHECK_STRNE(str1, str2)
-
-#define DCHECK_CONSTEXPR(x, out, dummy) \
-  (false && (x)) ? (dummy) :
-
+// DCHECKs are debug variants of CHECKs only enabled in debug builds. Generally CHECK should be
+// used unless profiling identifies a CHECK as being in performance critical code.
+#if defined(NDEBUG)
+static constexpr bool kEnableDChecks = false;
+#else
+static constexpr bool kEnableDChecks = true;
 #endif
 
-#define LOG(severity) ::art::LogMessage(__FILE__, __LINE__, severity, -1).stream()
-#define PLOG(severity) ::art::LogMessage(__FILE__, __LINE__, severity, errno).stream()
+#define DCHECK(x) if (::art::kEnableDChecks) CHECK(x)
+#define DCHECK_EQ(x, y) if (::art::kEnableDChecks) CHECK_EQ(x, y)
+#define DCHECK_NE(x, y) if (::art::kEnableDChecks) CHECK_NE(x, y)
+#define DCHECK_LE(x, y) if (::art::kEnableDChecks) CHECK_LE(x, y)
+#define DCHECK_LT(x, y) if (::art::kEnableDChecks) CHECK_LT(x, y)
+#define DCHECK_GE(x, y) if (::art::kEnableDChecks) CHECK_GE(x, y)
+#define DCHECK_GT(x, y) if (::art::kEnableDChecks) CHECK_GT(x, y)
+#define DCHECK_STREQ(s1, s2) if (::art::kEnableDChecks) CHECK_STREQ(s1, s2)
+#define DCHECK_STRNE(s1, s2) if (::art::kEnableDChecks) CHECK_STRNE(s1, s2)
+#if defined(NDEBUG)
+#define DCHECK_CONSTEXPR(x, out, dummy)
+#else
+#define DCHECK_CONSTEXPR(x, out, dummy) CHECK_CONSTEXPR(x, out, dummy)
+#endif
 
-#define LG LOG(INFO)
-
-#define UNIMPLEMENTED(level) LOG(level) << __PRETTY_FUNCTION__ << " unimplemented "
-
-#define VLOG_IS_ON(module) UNLIKELY(::art::gLogVerbosity.module)
-#define VLOG(module) if (VLOG_IS_ON(module)) ::art::LogMessage(__FILE__, __LINE__, INFO, -1).stream()
-#define VLOG_STREAM(module) ::art::LogMessage(__FILE__, __LINE__, INFO, -1).stream()
-
-//
-// Implementation details beyond this point.
-//
-
-namespace art {
-
+// Temporary class created to evaluate the LHS and RHS, used with MakeEagerEvaluator to infer the
+// types of LHS and RHS.
 template <typename LHS, typename RHS>
 struct EagerEvaluator {
   EagerEvaluator(LHS l, RHS r) : lhs(l), rhs(r) { }
@@ -156,10 +196,14 @@
   RHS rhs;
 };
 
-// We want char*s to be treated as pointers, not strings. If you want them treated like strings,
-// you'd need to use CHECK_STREQ and CHECK_STRNE anyway to compare the characters rather than their
-// addresses. We could express this more succinctly with std::remove_const, but this is quick and
-// easy to understand, and works before we have C++0x. We rely on signed/unsigned warnings to
+// Helper function for CHECK_xx.
+template <typename LHS, typename RHS>
+static inline EagerEvaluator<LHS, RHS> MakeEagerEvaluator(LHS lhs, RHS rhs) {
+  return EagerEvaluator<LHS, RHS>(lhs, rhs);
+}
+
+// Explicitly instantiate EagerEvalue for pointers so that char*s aren't treated as strings. To
+// compare strings use CHECK_STREQ and CHECK_STRNE. We rely on signed/unsigned warnings to
 // protect you against combinations not explicitly listed below.
 #define EAGER_PTR_EVALUATOR(T1, T2) \
   template <> struct EagerEvaluator<T1, T2> { \
@@ -182,153 +226,30 @@
 EAGER_PTR_EVALUATOR(signed char*, const signed char*);
 EAGER_PTR_EVALUATOR(signed char*, signed char*);
 
-template <typename LHS, typename RHS>
-EagerEvaluator<LHS, RHS> MakeEagerEvaluator(LHS lhs, RHS rhs) {
-  return EagerEvaluator<LHS, RHS>(lhs, rhs);
-}
+// Data for the log message, not stored in LogMessage to avoid increasing the stack size.
+class LogMessageData;
 
-// This indirection greatly reduces the stack impact of having
-// lots of checks/logging in a function.
-struct LogMessageData {
- public:
-  LogMessageData(const char* file, int line, LogSeverity severity, int error);
-  std::ostringstream buffer;
-  const char* const file;
-  const int line_number;
-  const LogSeverity severity;
-  const int error;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(LogMessageData);
-};
-
+// A LogMessage is a temporarily scoped object used by LOG and the unlikely part of a CHECK. The
+// destructor will abort if the severity is FATAL.
 class LogMessage {
  public:
-  LogMessage(const char* file, int line, LogSeverity severity, int error)
-    : data_(new LogMessageData(file, line, severity, error)) {
-  }
+  LogMessage(const char* file, unsigned int line, LogSeverity severity, int error);
 
   ~LogMessage();  // TODO: enable LOCKS_EXCLUDED(Locks::logging_lock_).
 
-  std::ostream& stream() {
-    return data_->buffer;
-  }
+  // Returns the stream associated with the message, the LogMessage performs output when it goes
+  // out of scope.
+  std::ostream& stream();
+
+  // The routine that performs the actual logging.
+  static void LogLine(const char* file, unsigned int line, LogSeverity severity, const char* msg);
 
  private:
-  static void LogLine(const LogMessageData& data, const char*);
-
   const std::unique_ptr<LogMessageData> data_;
 
-  friend void HandleUnexpectedSignal(int signal_number, siginfo_t* info, void* raw_context);
-  friend class Mutex;
   DISALLOW_COPY_AND_ASSIGN(LogMessage);
 };
 
-// A convenience to allow any class with a "Dump(std::ostream& os)" member function
-// but without an operator<< to be used as if it had an operator<<. Use like this:
-//
-//   os << Dumpable<MyType>(my_type_instance);
-//
-template<typename T>
-class Dumpable {
- public:
-  explicit Dumpable(T& value) : value_(value) {
-  }
-
-  void Dump(std::ostream& os) const {
-    value_.Dump(os);
-  }
-
- private:
-  T& value_;
-
-  DISALLOW_COPY_AND_ASSIGN(Dumpable);
-};
-
-template<typename T>
-std::ostream& operator<<(std::ostream& os, const Dumpable<T>& rhs) {
-  rhs.Dump(os);
-  return os;
-}
-
-template<typename T>
-class ConstDumpable {
- public:
-  explicit ConstDumpable(const T& value) : value_(value) {
-  }
-
-  void Dump(std::ostream& os) const {
-    value_.Dump(os);
-  }
-
- private:
-  const T& value_;
-
-  DISALLOW_COPY_AND_ASSIGN(ConstDumpable);
-};
-
-template<typename T>
-std::ostream& operator<<(std::ostream& os, const ConstDumpable<T>& rhs) {
-  rhs.Dump(os);
-  return os;
-}
-
-// Helps you use operator<< in a const char*-like context such as our various 'F' methods with
-// format strings.
-template<typename T>
-class ToStr {
- public:
-  explicit ToStr(const T& value) {
-    std::ostringstream os;
-    os << value;
-    s_ = os.str();
-  }
-
-  const char* c_str() const {
-    return s_.c_str();
-  }
-
-  const std::string& str() const {
-    return s_;
-  }
-
- private:
-  std::string s_;
-  DISALLOW_COPY_AND_ASSIGN(ToStr);
-};
-
-// The members of this struct are the valid arguments to VLOG and VLOG_IS_ON in code,
-// and the "-verbose:" command line argument.
-struct LogVerbosity {
-  bool class_linker;  // Enabled with "-verbose:class".
-  bool compiler;
-  bool gc;
-  bool heap;
-  bool jdwp;
-  bool jni;
-  bool monitor;
-  bool profiler;
-  bool signals;
-  bool startup;
-  bool third_party_jni;  // Enabled with "-verbose:third-party-jni".
-  bool threads;
-  bool verifier;
-};
-
-extern LogVerbosity gLogVerbosity;
-
-extern std::vector<std::string> gVerboseMethods;
-
-// Used on fatal exit. Prevents recursive aborts. Allows us to disable
-// some error checking to ensure fatal shutdown makes forward progress.
-extern unsigned int gAborting;
-
-extern void InitLogging(char* argv[]);
-
-extern const char* GetCmdLine();
-extern const char* ProgramInvocationName();
-extern const char* ProgramInvocationShortName();
-
 }  // namespace art
 
 #endif  // ART_RUNTIME_BASE_LOGGING_H_
diff --git a/runtime/base/logging_android.cc b/runtime/base/logging_android.cc
deleted file mode 100644
index 9b1ac58..0000000
--- a/runtime/base/logging_android.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "logging.h"
-
-#include <unistd.h>
-
-#include <iostream>
-
-#include "base/stringprintf.h"
-#include "cutils/log.h"
-
-namespace art {
-
-static const int kLogSeverityToAndroidLogPriority[] = {
-  ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN,
-  ANDROID_LOG_ERROR, ANDROID_LOG_FATAL, ANDROID_LOG_FATAL
-};
-
-void LogMessage::LogLine(const LogMessageData& data, const char* message) {
-  const char* tag = ProgramInvocationShortName();
-  int priority = kLogSeverityToAndroidLogPriority[data.severity];
-  if (priority == ANDROID_LOG_FATAL) {
-    LOG_PRI(priority, tag, "%s:%d] %s", data.file, data.line_number, message);
-  } else {
-    LOG_PRI(priority, tag, "%s", message);
-  }
-}
-
-}  // namespace art
diff --git a/runtime/base/logging_linux.cc b/runtime/base/logging_linux.cc
deleted file mode 100644
index 0399128..0000000
--- a/runtime/base/logging_linux.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "logging.h"
-
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <cstdio>
-#include <cstring>
-#include <iostream>
-
-#include "base/stringprintf.h"
-#include "utils.h"
-
-namespace art {
-
-void LogMessage::LogLine(const LogMessageData& data, const char* message) {
-  char severity = "VDIWEFF"[data.severity];
-  fprintf(stderr, "%s %c %5d %5d %s:%d] %s\n",
-          ProgramInvocationShortName(), severity, getpid(), ::art::GetTid(),
-          data.file, data.line_number, message);
-}
-
-}  // namespace art
diff --git a/runtime/base/macros.h b/runtime/base/macros.h
index bbe0f5a..febea61 100644
--- a/runtime/base/macros.h
+++ b/runtime/base/macros.h
@@ -63,22 +63,33 @@
 #define COMPILE_ASSERT(expr, msg) \
   typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] // NOLINT
 
-// DISALLOW_COPY_AND_ASSIGN disallows the copy and operator= functions.
-// It goes in the private: declarations in a class.
-#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
-  TypeName(const TypeName&);               \
-  void operator=(const TypeName&)
+// Declare a friend relationship in a class with a test. Used rather that FRIEND_TEST to avoid
+// globally importing gtest/gtest.h into the main ART header files.
+#define ART_FRIEND_TEST(test_set_name, individual_test)\
+friend class test_set_name##_##individual_test##_Test
 
-// A macro to disallow all the implicit constructors, namely the
-// default constructor, copy constructor and operator= functions.
+// DISALLOW_COPY_AND_ASSIGN disallows the copy and operator= functions. It goes in the private:
+// declarations in a class.
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+  TypeName(const TypeName&) = delete;  \
+  void operator=(const TypeName&) = delete
+
+// A macro to disallow all the implicit constructors, namely the default constructor, copy
+// constructor and operator= functions.
 //
-// This should be used in the private: declarations for a class
-// that wants to prevent anyone from instantiating it. This is
-// especially useful for classes containing only static methods.
+// This should be used in the private: declarations for a class that wants to prevent anyone from
+// instantiating it. This is especially useful for classes containing only static methods.
 #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
-  TypeName();                                    \
+  TypeName() = delete;  \
   DISALLOW_COPY_AND_ASSIGN(TypeName)
 
+// A macro to disallow new and delete operators for a class. It goes in the private: declarations.
+#define DISALLOW_ALLOCATION() \
+  public: \
+    ALWAYS_INLINE void operator delete(void*, size_t) { UNREACHABLE(); } \
+  private: \
+    void* operator new(size_t) = delete
+
 // The arraysize(arr) macro returns the # of elements in an array arr.
 // The expression is a compile-time constant, and therefore can be
 // used in defining new arrays, for example.  If you use arraysize on
@@ -177,7 +188,6 @@
 
 #define PURE __attribute__ ((__pure__))
 #define WARN_UNUSED __attribute__((warn_unused_result))
-#define NO_RETURN __attribute__((noreturn))
 
 template<typename T> void UNUSED(const T&) {}
 #define UNREACHABLE  __builtin_unreachable
diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h
index f70db35..e066787 100644
--- a/runtime/base/mutex-inl.h
+++ b/runtime/base/mutex-inl.h
@@ -21,11 +21,8 @@
 
 #include "mutex.h"
 
-#define ATRACE_TAG ATRACE_TAG_DALVIK
-
-#include "cutils/trace.h"
-
 #include "base/stringprintf.h"
+#include "base/value_object.h"
 #include "runtime.h"
 #include "thread.h"
 
@@ -44,35 +41,6 @@
 }
 #endif  // ART_USE_FUTEXES
 
-class ScopedContentionRecorder {
- public:
-  ScopedContentionRecorder(BaseMutex* mutex, uint64_t blocked_tid, uint64_t owner_tid)
-      : mutex_(kLogLockContentions ? mutex : NULL),
-        blocked_tid_(kLogLockContentions ? blocked_tid : 0),
-        owner_tid_(kLogLockContentions ? owner_tid : 0),
-        start_nano_time_(kLogLockContentions ? NanoTime() : 0) {
-    if (ATRACE_ENABLED()) {
-      std::string msg = StringPrintf("Lock contention on %s (owner tid: %" PRIu64 ")",
-                                     mutex->GetName(), owner_tid);
-      ATRACE_BEGIN(msg.c_str());
-    }
-  }
-
-  ~ScopedContentionRecorder() {
-    ATRACE_END();
-    if (kLogLockContentions) {
-      uint64_t end_nano_time = NanoTime();
-      mutex_->RecordContention(blocked_tid_, owner_tid_, end_nano_time - start_nano_time_);
-    }
-  }
-
- private:
-  BaseMutex* const mutex_;
-  const uint64_t blocked_tid_;
-  const uint64_t owner_tid_;
-  const uint64_t start_nano_time_;
-};
-
 static inline uint64_t SafeGetTid(const Thread* self) {
   if (self != NULL) {
     return static_cast<uint64_t>(self->GetTid());
@@ -158,15 +126,7 @@
       // Add as an extra reader.
       done = state_.CompareExchangeWeakAcquire(cur_state, cur_state + 1);
     } else {
-      // Owner holds it exclusively, hang up.
-      ScopedContentionRecorder scr(this, GetExclusiveOwnerTid(), SafeGetTid(self));
-      ++num_pending_readers_;
-      if (futex(state_.Address(), FUTEX_WAIT, cur_state, NULL, NULL, 0) != 0) {
-        if (errno != EAGAIN) {
-          PLOG(FATAL) << "futex wait failed for " << name_;
-        }
-      }
-      --num_pending_readers_;
+      HandleSharedLockContention(self, cur_state);
     }
   } while (!done);
 #else
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index cbcd408..423ea77 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -19,8 +19,12 @@
 #include <errno.h>
 #include <sys/time.h>
 
+#define ATRACE_TAG ATRACE_TAG_DALVIK
+#include "cutils/trace.h"
+
 #include "atomic.h"
 #include "base/logging.h"
+#include "base/value_object.h"
 #include "mutex-inl.h"
 #include "runtime.h"
 #include "scoped_thread_state_change.h"
@@ -83,22 +87,59 @@
 }
 #endif
 
-class ScopedAllMutexesLock {
+class ScopedAllMutexesLock FINAL {
  public:
   explicit ScopedAllMutexesLock(const BaseMutex* mutex) : mutex_(mutex) {
     while (!gAllMutexData->all_mutexes_guard.CompareExchangeWeakAcquire(0, mutex)) {
       NanoSleep(100);
     }
   }
+
   ~ScopedAllMutexesLock() {
+#if !defined(__clang__)
+    // TODO: remove this workaround target GCC/libc++/bionic bug "invalid failure memory model".
+    while (!gAllMutexData->all_mutexes_guard.CompareExchangeWeakSequentiallyConsistent(mutex_, 0)) {
+#else
     while (!gAllMutexData->all_mutexes_guard.CompareExchangeWeakRelease(mutex_, 0)) {
+#endif
       NanoSleep(100);
     }
   }
+
  private:
   const BaseMutex* const mutex_;
 };
 
+// Scoped class that generates events at the beginning and end of lock contention.
+class ScopedContentionRecorder FINAL : public ValueObject {
+ public:
+  ScopedContentionRecorder(BaseMutex* mutex, uint64_t blocked_tid, uint64_t owner_tid)
+      : mutex_(kLogLockContentions ? mutex : NULL),
+        blocked_tid_(kLogLockContentions ? blocked_tid : 0),
+        owner_tid_(kLogLockContentions ? owner_tid : 0),
+        start_nano_time_(kLogLockContentions ? NanoTime() : 0) {
+    if (ATRACE_ENABLED()) {
+      std::string msg = StringPrintf("Lock contention on %s (owner tid: %" PRIu64 ")",
+                                     mutex->GetName(), owner_tid);
+      ATRACE_BEGIN(msg.c_str());
+    }
+  }
+
+  ~ScopedContentionRecorder() {
+    ATRACE_END();
+    if (kLogLockContentions) {
+      uint64_t end_nano_time = NanoTime();
+      mutex_->RecordContention(blocked_tid_, owner_tid_, end_nano_time - start_nano_time_);
+    }
+  }
+
+ private:
+  BaseMutex* const mutex_;
+  const uint64_t blocked_tid_;
+  const uint64_t owner_tid_;
+  const uint64_t start_nano_time_;
+};
+
 BaseMutex::BaseMutex(const char* name, LockLevel level) : level_(level), name_(name) {
   if (kLogLockContentions) {
     ScopedAllMutexesLock mu(this);
@@ -421,9 +462,9 @@
         if (this != Locks::logging_lock_) {
           LOG(FATAL) << "Unexpected state_ in unlock " << cur_state << " for " << name_;
         } else {
-          LogMessageData data(__FILE__, __LINE__, INTERNAL_FATAL, -1);
-          LogMessage::LogLine(data, StringPrintf("Unexpected state_ %d in unlock for %s",
-                                                 cur_state, name_).c_str());
+          LogMessage::LogLine(__FILE__, __LINE__, INTERNAL_FATAL,
+                              StringPrintf("Unexpected state_ %d in unlock for %s",
+                                           cur_state, name_).c_str());
           _exit(1);
         }
       }
@@ -605,6 +646,20 @@
 }
 #endif
 
+#if ART_USE_FUTEXES
+void ReaderWriterMutex::HandleSharedLockContention(Thread* self, int32_t cur_state) {
+  // Owner holds it exclusively, hang up.
+  ScopedContentionRecorder scr(this, GetExclusiveOwnerTid(), SafeGetTid(self));
+  ++num_pending_readers_;
+  if (futex(state_.Address(), FUTEX_WAIT, cur_state, NULL, NULL, 0) != 0) {
+    if (errno != EAGAIN) {
+      PLOG(FATAL) << "futex wait failed for " << name_;
+    }
+  }
+  --num_pending_readers_;
+}
+#endif
+
 bool ReaderWriterMutex::SharedTryLock(Thread* self) {
   DCHECK(self == NULL || self == Thread::Current());
 #if ART_USE_FUTEXES
@@ -673,7 +728,7 @@
   CHECK_MUTEX_CALL(pthread_condattr_init, (&cond_attrs));
 #if !defined(__APPLE__)
   // Apple doesn't have CLOCK_MONOTONIC or pthread_condattr_setclock.
-  CHECK_MUTEX_CALL(pthread_condattr_setclock(&cond_attrs, CLOCK_MONOTONIC));
+  CHECK_MUTEX_CALL(pthread_condattr_setclock, (&cond_attrs, CLOCK_MONOTONIC));
 #endif
   CHECK_MUTEX_CALL(pthread_cond_init, (&cond_, &cond_attrs));
 #endif
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 516fa07..628231a 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -361,6 +361,9 @@
 
  private:
 #if ART_USE_FUTEXES
+  // Out-of-inline path for handling contention for a SharedLock.
+  void HandleSharedLockContention(Thread* self, int32_t cur_state);
+
   // -1 implies held exclusive, +ve shared held by state_ many owners.
   AtomicInteger state_;
   // Exclusive owner. Modification guarded by this mutex.
diff --git a/runtime/base/stringpiece.cc b/runtime/base/stringpiece.cc
index 824ee48..2570bad 100644
--- a/runtime/base/stringpiece.cc
+++ b/runtime/base/stringpiece.cc
@@ -16,7 +16,7 @@
 
 #include "stringpiece.h"
 
-#include <iostream>
+#include <ostream>
 #include <utility>
 
 #include "logging.h"
diff --git a/runtime/base/to_str.h b/runtime/base/to_str.h
new file mode 100644
index 0000000..6b1c84c
--- /dev/null
+++ b/runtime/base/to_str.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#ifndef ART_RUNTIME_BASE_TO_STR_H_
+#define ART_RUNTIME_BASE_TO_STR_H_
+
+#include <sstream>
+
+namespace art {
+
+// Helps you use operator<< in a const char*-like context such as our various 'F' methods with
+// format strings.
+template<typename T>
+class ToStr {
+ public:
+  explicit ToStr(const T& value) {
+    std::ostringstream os;
+    os << value;
+    s_ = os.str();
+  }
+
+  const char* c_str() const {
+    return s_.c_str();
+  }
+
+  const std::string& str() const {
+    return s_;
+  }
+
+ private:
+  std::string s_;
+  DISALLOW_COPY_AND_ASSIGN(ToStr);
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_BASE_TO_STR_H_
diff --git a/runtime/base/unix_file/mapped_file.cc b/runtime/base/unix_file/mapped_file.cc
index 63927b1..77f4d02 100644
--- a/runtime/base/unix_file/mapped_file.cc
+++ b/runtime/base/unix_file/mapped_file.cc
@@ -42,7 +42,7 @@
   struct stat st;
   int result = TEMP_FAILURE_RETRY(fstat(Fd(), &st));
   if (result == -1) {
-    PLOG(WARNING) << "Failed to stat file '" << GetPath() << "'";
+    PLOG(::art::WARNING) << "Failed to stat file '" << GetPath() << "'";
     return false;
   }
   file_size_ = st.st_size;
@@ -50,8 +50,8 @@
     mapped_file_ = mmap(NULL, file_size_, PROT_READ, MAP_PRIVATE, Fd(), 0);
   } while (mapped_file_ == MAP_FAILED && errno == EINTR);
   if (mapped_file_ == MAP_FAILED) {
-    PLOG(WARNING) << "Failed to mmap file '" << GetPath() << "' of size "
-                  << file_size_ << " bytes to memory";
+    PLOG(::art::WARNING) << "Failed to mmap file '" << GetPath() << "' of size "
+        << file_size_ << " bytes to memory";
     return false;
   }
   map_mode_ = kMapReadOnly;
@@ -67,8 +67,7 @@
   int result = TEMP_FAILURE_RETRY(ftruncate(Fd(), file_size));
 #endif
   if (result == -1) {
-    PLOG(ERROR) << "Failed to truncate file '" << GetPath()
-                << "' to size " << file_size;
+    PLOG(::art::ERROR) << "Failed to truncate file '" << GetPath() << "' to size " << file_size;
     return false;
   }
   file_size_ = file_size;
@@ -77,7 +76,7 @@
         mmap(NULL, file_size_, PROT_READ | PROT_WRITE, MAP_SHARED, Fd(), 0);
   } while (mapped_file_ == MAP_FAILED && errno == EINTR);
   if (mapped_file_ == MAP_FAILED) {
-    PLOG(WARNING) << "Failed to mmap file '" << GetPath() << "' of size "
+    PLOG(::art::WARNING) << "Failed to mmap file '" << GetPath() << "' of size "
                   << file_size_ << " bytes to memory";
     return false;
   }
@@ -89,8 +88,7 @@
   CHECK(IsMapped());
   int result = TEMP_FAILURE_RETRY(munmap(mapped_file_, file_size_));
   if (result == -1) {
-    PLOG(WARNING) << "Failed unmap file '" << GetPath() << "' of size "
-                  << file_size_;
+    PLOG(::art::WARNING) << "Failed unmap file '" << GetPath() << "' of size " << file_size_;
     return false;
   } else {
     mapped_file_ = NULL;
diff --git a/runtime/base/value_object.h b/runtime/base/value_object.h
index ee0e2a0..8c752a9 100644
--- a/runtime/base/value_object.h
+++ b/runtime/base/value_object.h
@@ -17,19 +17,13 @@
 #ifndef ART_RUNTIME_BASE_VALUE_OBJECT_H_
 #define ART_RUNTIME_BASE_VALUE_OBJECT_H_
 
-#include "base/logging.h"
+#include "base/macros.h"
 
 namespace art {
 
 class ValueObject {
- public:
-  void* operator new(size_t size) {
-    LOG(FATAL) << "UNREACHABLE";
-    abort();
-  }
-  void operator delete(void*, size_t) {
-    LOG(FATAL) << "UNREACHABLE";
-  }
+ private:
+  DISALLOW_ALLOCATION();
 };
 
 }  // namespace art
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index fec1824..b2df091 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -20,6 +20,7 @@
 #include <zlib.h>
 
 #include "base/logging.h"
+#include "base/to_str.h"
 #include "class_linker.h"
 #include "class_linker-inl.h"
 #include "dex_file-inl.h"
diff --git a/runtime/check_reference_map_visitor.h b/runtime/check_reference_map_visitor.h
index 1a78d72..9d2d59c 100644
--- a/runtime/check_reference_map_visitor.h
+++ b/runtime/check_reference_map_visitor.h
@@ -37,7 +37,7 @@
       CHECK_EQ(GetDexPc(), DexFile::kDexNoIndex);
     }
 
-    if (!m || m->IsNative() || m->IsRuntimeMethod() || IsShadowFrame()) {
+    if (m == nullptr || m->IsNative() || m->IsRuntimeMethod() || IsShadowFrame()) {
       return true;
     }
 
@@ -84,8 +84,12 @@
         case DexRegisterMap::kInRegister:
           CHECK_NE(register_mask & dex_register_map.GetValue(reg), 0u);
           break;
+        case DexRegisterMap::kInFpuRegister:
+          // In Fpu register, should not be a reference.
+          CHECK(false);
+          break;
         case DexRegisterMap::kConstant:
-          CHECK_EQ(dex_register_map.GetValue(0), 0);
+          CHECK_EQ(dex_register_map.GetValue(reg), 0);
           break;
       }
     }
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index cf3a581..f6717fb 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -17,6 +17,7 @@
 #include "class_linker.h"
 
 #include <deque>
+#include <iostream>
 #include <memory>
 #include <queue>
 #include <string>
@@ -32,6 +33,7 @@
 #include "compiler_callbacks.h"
 #include "debugger.h"
 #include "dex_file-inl.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
 #include "gc_root-inl.h"
 #include "gc/accounting/card_table-inl.h"
 #include "gc/accounting/heap_bitmap.h"
@@ -115,7 +117,17 @@
   }
 }
 
-static void WrapExceptionInInitializer() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+static void VlogClassInitializationFailure(Handle<mirror::Class> klass)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (VLOG_IS_ON(class_linker)) {
+    std::string temp;
+    LOG(INFO) << "Failed to initialize class " << klass->GetDescriptor(&temp) << " from "
+              << klass->GetLocation() << "\n" << Thread::Current()->GetException(nullptr)->Dump();
+  }
+}
+
+static void WrapExceptionInInitializer(Handle<mirror::Class> klass)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   Thread* self = Thread::Current();
   JNIEnv* env = self->GetJniEnv();
 
@@ -132,6 +144,7 @@
     self->ThrowNewWrappedException(throw_location, "Ljava/lang/ExceptionInInitializerError;",
                                    nullptr);
   }
+  VlogClassInitializationFailure(klass);
 }
 
 static size_t Hash(const char* s) {
@@ -225,44 +238,6 @@
   }
 }
 
-const char* ClassLinker::class_roots_descriptors_[] = {
-  "Ljava/lang/Class;",
-  "Ljava/lang/Object;",
-  "[Ljava/lang/Class;",
-  "[Ljava/lang/Object;",
-  "Ljava/lang/String;",
-  "Ljava/lang/DexCache;",
-  "Ljava/lang/ref/Reference;",
-  "Ljava/lang/reflect/ArtField;",
-  "Ljava/lang/reflect/ArtMethod;",
-  "Ljava/lang/reflect/Proxy;",
-  "[Ljava/lang/String;",
-  "[Ljava/lang/reflect/ArtField;",
-  "[Ljava/lang/reflect/ArtMethod;",
-  "Ljava/lang/ClassLoader;",
-  "Ljava/lang/Throwable;",
-  "Ljava/lang/ClassNotFoundException;",
-  "Ljava/lang/StackTraceElement;",
-  "Z",
-  "B",
-  "C",
-  "D",
-  "F",
-  "I",
-  "J",
-  "S",
-  "V",
-  "[Z",
-  "[B",
-  "[C",
-  "[D",
-  "[F",
-  "[I",
-  "[J",
-  "[S",
-  "[Ljava/lang/StackTraceElement;",
-};
-
 ClassLinker::ClassLinker(InternTable* intern_table)
     // dex_lock_ is recursive as it may be used in stack dumping.
     : dex_lock_("ClassLinker dex lock", kDefaultMutexLevel),
@@ -281,16 +256,9 @@
       quick_imt_conflict_trampoline_(nullptr),
       quick_generic_jni_trampoline_(nullptr),
       quick_to_interpreter_bridge_trampoline_(nullptr) {
-  CHECK_EQ(arraysize(class_roots_descriptors_), size_t(kClassRootsMax));
   memset(find_array_class_cache_, 0, kFindArrayCacheSize * sizeof(mirror::Class*));
 }
 
-// To set a value for generic JNI. May be necessary in compiler tests.
-extern "C" void art_quick_generic_jni_trampoline(mirror::ArtMethod*);
-extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*);
-extern "C" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*);
-extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*);
-
 void ClassLinker::InitWithoutImage(const std::vector<const DexFile*>& boot_class_path) {
   VLOG(startup) << "ClassLinker::Init";
   CHECK(!Runtime::Current()->GetHeap()->HasImageSpace()) << "Runtime has image. We should use it.";
@@ -471,12 +439,12 @@
 
   // Set up GenericJNI entrypoint. That is mainly a hack for common_compiler_test.h so that
   // we do not need friend classes or a publicly exposed setter.
-  quick_generic_jni_trampoline_ = reinterpret_cast<void*>(art_quick_generic_jni_trampoline);
+  quick_generic_jni_trampoline_ = GetQuickGenericJniStub();
   if (!runtime->IsCompiler()) {
     // We need to set up the generic trampolines since we don't have an image.
-    quick_resolution_trampoline_ = reinterpret_cast<void*>(art_quick_resolution_trampoline);
-    quick_imt_conflict_trampoline_ = reinterpret_cast<void*>(art_quick_imt_conflict_trampoline);
-    quick_to_interpreter_bridge_trampoline_ = reinterpret_cast<void*>(art_quick_to_interpreter_bridge);
+    quick_resolution_trampoline_ = GetQuickResolutionStub();
+    quick_imt_conflict_trampoline_ = GetQuickImtConflictStub();
+    quick_to_interpreter_bridge_trampoline_ = GetQuickToInterpreterBridge();
   }
 
   // Object, String and DexCache need to be rerun through FindSystemClass to finish init
@@ -560,15 +528,15 @@
   CHECK_EQ(java_lang_reflect_ArtField.Get(), Art_field_class);
 
   mirror::Class* String_array_class =
-      FindSystemClass(self, class_roots_descriptors_[kJavaLangStringArrayClass]);
+      FindSystemClass(self, GetClassRootDescriptor(kJavaLangStringArrayClass));
   CHECK_EQ(object_array_string.Get(), String_array_class);
 
   mirror::Class* Art_method_array_class =
-      FindSystemClass(self, class_roots_descriptors_[kJavaLangReflectArtMethodArrayClass]);
+      FindSystemClass(self, GetClassRootDescriptor(kJavaLangReflectArtMethodArrayClass));
   CHECK_EQ(object_array_art_method.Get(), Art_method_array_class);
 
   mirror::Class* Art_field_array_class =
-      FindSystemClass(self, class_roots_descriptors_[kJavaLangReflectArtFieldArrayClass]);
+      FindSystemClass(self, GetClassRootDescriptor(kJavaLangReflectArtFieldArrayClass));
   CHECK_EQ(object_array_art_field.Get(), Art_field_array_class);
 
   // End of special init trickery, subsequent classes may be loaded via FindSystemClass.
@@ -1655,7 +1623,7 @@
   if (obj->IsArtMethod()) {
     mirror::ArtMethod* method = obj->AsArtMethod();
     if (!method->IsNative()) {
-      method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge);
+      method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge);
       if (method != Runtime::Current()->GetResolutionMethod()) {
         method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
         method->SetEntryPointFromPortableCompiledCode(GetPortableToInterpreterBridge());
@@ -2524,7 +2492,7 @@
   if (result == nullptr) {
     if (method->IsNative()) {
       // No code and native? Use generic trampoline.
-      result = GetQuickGenericJniTrampoline();
+      result = GetQuickGenericJniStub();
     } else if (method->IsPortableCompiled()) {
       // No code? Do we expect portable code?
       result = GetQuickToPortableBridge();
@@ -2678,7 +2646,7 @@
       // Use interpreter entry point.
       // Check whether the method is native, in which case it's generic JNI.
       if (quick_code == nullptr && portable_code == nullptr && method->IsNative()) {
-        quick_code = GetQuickGenericJniTrampoline();
+        quick_code = GetQuickGenericJniStub();
         portable_code = GetPortableToQuickBridge();
       } else {
         portable_code = GetPortableToInterpreterBridge();
@@ -2704,7 +2672,8 @@
                            const OatFile::OatClass* oat_class,
                            const DexFile& dex_file, uint32_t dex_method_index,
                            uint32_t method_index) {
-  if (Runtime::Current()->IsCompiler()) {
+  Runtime* runtime = Runtime::Current();
+  if (runtime->IsCompiler()) {
     // The following code only applies to a non-compiler runtime.
     return;
   }
@@ -2723,7 +2692,7 @@
                                             method->GetEntryPointFromQuickCompiledCode(),
                                             method->GetEntryPointFromPortableCompiledCode());
   if (enter_interpreter && !method->IsNative()) {
-    method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge);
+    method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge);
   } else {
     method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
   }
@@ -2739,15 +2708,15 @@
     // For static methods excluding the class initializer, install the trampoline.
     // It will be replaced by the proper entry point by ClassLinker::FixupStaticTrampolines
     // after initializing class (see ClassLinker::InitializeClass method).
-    method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionTrampoline());
-    method->SetEntryPointFromPortableCompiledCode(GetPortableResolutionTrampoline());
+    method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionStub());
+    method->SetEntryPointFromPortableCompiledCode(GetPortableResolutionStub());
   } else if (enter_interpreter) {
     if (!method->IsNative()) {
       // Set entry point from compiled code if there's no code or in interpreter only mode.
       method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
       method->SetEntryPointFromPortableCompiledCode(GetPortableToInterpreterBridge());
     } else {
-      method->SetEntryPointFromQuickCompiledCode(GetQuickGenericJniTrampoline());
+      method->SetEntryPointFromQuickCompiledCode(GetQuickGenericJniStub());
       method->SetEntryPointFromPortableCompiledCode(GetPortableToQuickBridge());
     }
   } else if (method->GetEntryPointFromPortableCompiledCode() != nullptr) {
@@ -2761,18 +2730,18 @@
 
   if (method->IsNative()) {
     // Unregistering restores the dlsym lookup stub.
-    method->UnregisterNative(Thread::Current());
+    method->UnregisterNative();
 
     if (enter_interpreter) {
-      // We have a native method here without code. Then it should have either the GenericJni
-      // trampoline as entrypoint (non-static), or the Resolution trampoline (static).
-      DCHECK(method->GetEntryPointFromQuickCompiledCode() == GetQuickResolutionTrampoline()
-          || method->GetEntryPointFromQuickCompiledCode() == GetQuickGenericJniTrampoline());
+      // We have a native method here without code. Then it should have either the generic JNI
+      // trampoline as entrypoint (non-static), or the resolution trampoline (static).
+      // TODO: this doesn't handle all the cases where trampolines may be installed.
+      const void* entry_point = method->GetEntryPointFromQuickCompiledCode();
+      DCHECK(IsQuickGenericJniStub(entry_point) || IsQuickResolutionStub(entry_point));
     }
   }
 
   // Allow instrumentation its chance to hijack code.
-  Runtime* runtime = Runtime::Current();
   runtime->GetInstrumentation()->UpdateMethodsCode(method.Get(),
                                                    method->GetEntryPointFromQuickCompiledCode(),
                                                    method->GetEntryPointFromPortableCompiledCode(),
@@ -3213,13 +3182,13 @@
       new_class.Assign(GetClassRoot(kClassArrayClass));
     } else if (strcmp(descriptor, "[Ljava/lang/Object;") == 0) {
       new_class.Assign(GetClassRoot(kObjectArrayClass));
-    } else if (strcmp(descriptor, class_roots_descriptors_[kJavaLangStringArrayClass]) == 0) {
+    } else if (strcmp(descriptor, GetClassRootDescriptor(kJavaLangStringArrayClass)) == 0) {
       new_class.Assign(GetClassRoot(kJavaLangStringArrayClass));
     } else if (strcmp(descriptor,
-                      class_roots_descriptors_[kJavaLangReflectArtMethodArrayClass]) == 0) {
+                      GetClassRootDescriptor(kJavaLangReflectArtMethodArrayClass)) == 0) {
       new_class.Assign(GetClassRoot(kJavaLangReflectArtMethodArrayClass));
     } else if (strcmp(descriptor,
-                      class_roots_descriptors_[kJavaLangReflectArtFieldArrayClass]) == 0) {
+                      GetClassRootDescriptor(kJavaLangReflectArtFieldArrayClass)) == 0) {
       new_class.Assign(GetClassRoot(kJavaLangReflectArtFieldArrayClass));
     } else if (strcmp(descriptor, "[C") == 0) {
       new_class.Assign(GetClassRoot(kCharArrayClass));
@@ -4151,6 +4120,7 @@
     // Was the class already found to be erroneous? Done under the lock to match the JLS.
     if (klass->IsErroneous()) {
       ThrowEarlierClassFailure(klass.Get());
+      VlogClassInitializationFailure(klass);
       return false;
     }
 
@@ -4163,6 +4133,7 @@
         // compile time.
         if (klass->IsErroneous()) {
           CHECK(self->IsExceptionPending());
+          VlogClassInitializationFailure(klass);
         } else {
           CHECK(Runtime::Current()->IsCompiler());
           CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime);
@@ -4181,6 +4152,7 @@
     if (klass->GetStatus() == mirror::Class::kStatusInitializing) {
       // Could have got an exception during verification.
       if (self->IsExceptionPending()) {
+        VlogClassInitializationFailure(klass);
         return false;
       }
       // We caught somebody else in the act; was it us?
@@ -4277,7 +4249,7 @@
     ObjectLock<mirror::Class> lock(self, klass);
 
     if (self->IsExceptionPending()) {
-      WrapExceptionInInitializer();
+      WrapExceptionInInitializer(klass);
       klass->SetStatus(mirror::Class::kStatusError, self);
       success = false;
     } else {
@@ -4311,9 +4283,9 @@
 
     // When we wake up, repeat the test for init-in-progress.  If
     // there's an exception pending (only possible if
-    // "interruptShouldThrow" was set), bail out.
+    // we were not using WaitIgnoringInterrupts), bail out.
     if (self->IsExceptionPending()) {
-      WrapExceptionInInitializer();
+      WrapExceptionInInitializer(klass);
       klass->SetStatus(mirror::Class::kStatusError, self);
       return false;
     }
@@ -4330,6 +4302,7 @@
       // different thread.  Synthesize one here.
       ThrowNoClassDefFoundError("<clinit> failed for class %s; see exception in other thread",
                                 PrettyDescriptor(klass.Get()).c_str());
+      VlogClassInitializationFailure(klass);
       return false;
     }
     if (klass->IsInitialized()) {
@@ -5138,7 +5111,7 @@
     bool seen_non_ref = false;
     for (size_t i = 0; i < num_fields; i++) {
       mirror::ArtField* field = fields->Get(i);
-      if (false) {  // enable to debug field layout
+      if ((false)) {  // enable to debug field layout
         LOG(INFO) << "LinkFields: " << (is_static ? "static" : "instance")
                     << " class=" << PrettyClass(klass.Get())
                     << " field=" << PrettyField(field)
@@ -5531,6 +5504,84 @@
   }
 }
 
+static OatFile::OatMethod CreateOatMethod(const void* code, const uint8_t* gc_map,
+                                          bool is_portable) {
+  CHECK_EQ(kUsePortableCompiler, is_portable);
+  CHECK(code != nullptr);
+  const uint8_t* base;
+  uint32_t code_offset, gc_map_offset;
+  if (gc_map == nullptr) {
+    base = reinterpret_cast<const uint8_t*>(code);  // Base of data points at code.
+    base -= sizeof(void*);  // Move backward so that code_offset != 0.
+    code_offset = sizeof(void*);
+    gc_map_offset = 0;
+  } else {
+    // TODO: 64bit support.
+    base = nullptr;  // Base of data in oat file, ie 0.
+    code_offset = PointerToLowMemUInt32(code);
+    gc_map_offset = PointerToLowMemUInt32(gc_map);
+  }
+  return OatFile::OatMethod(base, code_offset, gc_map_offset);
+}
+
+bool ClassLinker::IsPortableResolutionStub(const void* entry_point) const {
+  return (entry_point == GetPortableResolutionStub()) ||
+      (portable_resolution_trampoline_ == entry_point);
+}
+
+bool ClassLinker::IsQuickResolutionStub(const void* entry_point) const {
+  return (entry_point == GetQuickResolutionStub()) ||
+      (quick_resolution_trampoline_ == entry_point);
+}
+
+bool ClassLinker::IsPortableToInterpreterBridge(const void* entry_point) const {
+  return (entry_point == GetPortableToInterpreterBridge());
+  // TODO: portable_to_interpreter_bridge_trampoline_ == entry_point;
+}
+
+bool ClassLinker::IsQuickToInterpreterBridge(const void* entry_point) const {
+  return (entry_point == GetQuickToInterpreterBridge()) ||
+      (quick_to_interpreter_bridge_trampoline_ == entry_point);
+}
+
+bool ClassLinker::IsQuickGenericJniStub(const void* entry_point) const {
+  return (entry_point == GetQuickGenericJniStub()) ||
+      (quick_generic_jni_trampoline_ == entry_point);
+}
+
+const void* ClassLinker::GetRuntimeQuickGenericJniStub() const {
+  return GetQuickGenericJniStub();
+}
+
+void ClassLinker::SetEntryPointsToCompiledCode(mirror::ArtMethod* method, const void* method_code,
+                                               bool is_portable) const {
+  OatFile::OatMethod oat_method = CreateOatMethod(method_code, nullptr, is_portable);
+  oat_method.LinkMethod(method);
+  method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
+  // Create bridges to transition between different kinds of compiled bridge.
+  if (method->GetEntryPointFromPortableCompiledCode() == nullptr) {
+    method->SetEntryPointFromPortableCompiledCode(GetPortableToQuickBridge());
+  } else {
+    CHECK(method->GetEntryPointFromQuickCompiledCode() == nullptr);
+    method->SetEntryPointFromQuickCompiledCode(GetQuickToPortableBridge());
+    method->SetIsPortableCompiled();
+  }
+}
+
+void ClassLinker::SetEntryPointsToInterpreter(mirror::ArtMethod* method) const {
+  if (!method->IsNative()) {
+    method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge);
+    method->SetEntryPointFromPortableCompiledCode(GetPortableToInterpreterBridge());
+    method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
+  } else {
+    const void* quick_method_code = GetQuickGenericJniStub();
+    OatFile::OatMethod oat_method = CreateOatMethod(quick_method_code, nullptr, false);
+    oat_method.LinkMethod(method);
+    method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
+    method->SetEntryPointFromPortableCompiledCode(GetPortableToQuickBridge());
+  }
+}
+
 void ClassLinker::DumpForSigQuit(std::ostream& os) {
   Thread* self = Thread::Current();
   if (dex_cache_image_class_lookup_required_) {
@@ -5569,4 +5620,50 @@
   class_roots->Set<false>(class_root, klass);
 }
 
+const char* ClassLinker::GetClassRootDescriptor(ClassRoot class_root) {
+  static const char* class_roots_descriptors[] = {
+    "Ljava/lang/Class;",
+    "Ljava/lang/Object;",
+    "[Ljava/lang/Class;",
+    "[Ljava/lang/Object;",
+    "Ljava/lang/String;",
+    "Ljava/lang/DexCache;",
+    "Ljava/lang/ref/Reference;",
+    "Ljava/lang/reflect/ArtField;",
+    "Ljava/lang/reflect/ArtMethod;",
+    "Ljava/lang/reflect/Proxy;",
+    "[Ljava/lang/String;",
+    "[Ljava/lang/reflect/ArtField;",
+    "[Ljava/lang/reflect/ArtMethod;",
+    "Ljava/lang/ClassLoader;",
+    "Ljava/lang/Throwable;",
+    "Ljava/lang/ClassNotFoundException;",
+    "Ljava/lang/StackTraceElement;",
+    "Z",
+    "B",
+    "C",
+    "D",
+    "F",
+    "I",
+    "J",
+    "S",
+    "V",
+    "[Z",
+    "[B",
+    "[C",
+    "[D",
+    "[F",
+    "[I",
+    "[J",
+    "[S",
+    "[Ljava/lang/StackTraceElement;",
+  };
+  COMPILE_ASSERT(arraysize(class_roots_descriptors) == size_t(kClassRootsMax),
+                 mismatch_between_class_descriptors_and_class_root_enum);
+
+  const char* descriptor = class_roots_descriptors[class_root];
+  CHECK(descriptor != nullptr);
+  return descriptor;
+}
+
 }  // namespace art
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 373fa89..1847926 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -27,7 +27,6 @@
 #include "base/mutex.h"
 #include "dex_file.h"
 #include "gc_root.h"
-#include "gtest/gtest.h"
 #include "jni.h"
 #include "oat_file.h"
 #include "object_callbacks.h"
@@ -60,6 +59,46 @@
 
 class ClassLinker {
  public:
+  // Well known mirror::Class roots accessed via GetClassRoot.
+  enum ClassRoot {
+    kJavaLangClass,
+    kJavaLangObject,
+    kClassArrayClass,
+    kObjectArrayClass,
+    kJavaLangString,
+    kJavaLangDexCache,
+    kJavaLangRefReference,
+    kJavaLangReflectArtField,
+    kJavaLangReflectArtMethod,
+    kJavaLangReflectProxy,
+    kJavaLangStringArrayClass,
+    kJavaLangReflectArtFieldArrayClass,
+    kJavaLangReflectArtMethodArrayClass,
+    kJavaLangClassLoader,
+    kJavaLangThrowable,
+    kJavaLangClassNotFoundException,
+    kJavaLangStackTraceElement,
+    kPrimitiveBoolean,
+    kPrimitiveByte,
+    kPrimitiveChar,
+    kPrimitiveDouble,
+    kPrimitiveFloat,
+    kPrimitiveInt,
+    kPrimitiveLong,
+    kPrimitiveShort,
+    kPrimitiveVoid,
+    kBooleanArrayClass,
+    kByteArrayClass,
+    kCharArrayClass,
+    kDoubleArrayClass,
+    kFloatArrayClass,
+    kIntArrayClass,
+    kLongArrayClass,
+    kShortArrayClass,
+    kJavaLangStackTraceElementArrayClass,
+    kClassRootsMax,
+  };
+
   explicit ClassLinker(InternTable* intern_table);
   ~ClassLinker();
 
@@ -371,34 +410,38 @@
   pid_t GetClassesLockOwner();  // For SignalCatcher.
   pid_t GetDexLockOwner();  // For SignalCatcher.
 
-  const void* GetPortableResolutionTrampoline() const {
-    return portable_resolution_trampoline_;
-  }
+  mirror::Class* GetClassRoot(ClassRoot class_root) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  const void* GetQuickGenericJniTrampoline() const {
-    return quick_generic_jni_trampoline_;
-  }
+  static const char* GetClassRootDescriptor(ClassRoot class_root);
 
-  const void* GetQuickResolutionTrampoline() const {
-    return quick_resolution_trampoline_;
-  }
+  // Is the given entry point portable code to run the resolution stub?
+  bool IsPortableResolutionStub(const void* entry_point) const;
 
-  const void* GetPortableImtConflictTrampoline() const {
-    return portable_imt_conflict_trampoline_;
-  }
+  // Is the given entry point quick code to run the resolution stub?
+  bool IsQuickResolutionStub(const void* entry_point) const;
 
-  const void* GetQuickImtConflictTrampoline() const {
-    return quick_imt_conflict_trampoline_;
-  }
+  // Is the given entry point portable code to bridge into the interpreter?
+  bool IsPortableToInterpreterBridge(const void* entry_point) const;
 
-  const void* GetQuickToInterpreterBridgeTrampoline() const {
-    return quick_to_interpreter_bridge_trampoline_;
-  }
+  // Is the given entry point quick code to bridge into the interpreter?
+  bool IsQuickToInterpreterBridge(const void* entry_point) const;
+
+  // Is the given entry point quick code to run the generic JNI stub?
+  bool IsQuickGenericJniStub(const void* entry_point) const;
 
   InternTable* GetInternTable() const {
     return intern_table_;
   }
 
+  // Set the entrypoints up for method to the given code.
+  void SetEntryPointsToCompiledCode(mirror::ArtMethod* method, const void* method_code,
+                                    bool is_portable) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Set the entrypoints up for method to the enter the interpreter.
+  void SetEntryPointsToInterpreter(mirror::ArtMethod* method) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Attempts to insert a class into a class table.  Returns NULL if
   // the class was inserted, otherwise returns an existing class with
   // the same descriptor and ClassLoader.
@@ -668,6 +711,12 @@
   void FixupTemporaryDeclaringClass(mirror::Class* temp_class, mirror::Class* new_class)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  void SetClassRoot(ClassRoot class_root, mirror::Class* klass)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Return the quick generic JNI stub for testing.
+  const void* GetRuntimeQuickGenericJniStub() const;
+
   std::vector<const DexFile*> boot_class_path_;
 
   mutable ReaderWriterMutex dex_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
@@ -691,61 +740,9 @@
   // the classes into the class_table_ to avoid dex cache based searches.
   Atomic<uint32_t> failed_dex_cache_class_lookups_;
 
-  // indexes into class_roots_.
-  // needs to be kept in sync with class_roots_descriptors_.
-  enum ClassRoot {
-    kJavaLangClass,
-    kJavaLangObject,
-    kClassArrayClass,
-    kObjectArrayClass,
-    kJavaLangString,
-    kJavaLangDexCache,
-    kJavaLangRefReference,
-    kJavaLangReflectArtField,
-    kJavaLangReflectArtMethod,
-    kJavaLangReflectProxy,
-    kJavaLangStringArrayClass,
-    kJavaLangReflectArtFieldArrayClass,
-    kJavaLangReflectArtMethodArrayClass,
-    kJavaLangClassLoader,
-    kJavaLangThrowable,
-    kJavaLangClassNotFoundException,
-    kJavaLangStackTraceElement,
-    kPrimitiveBoolean,
-    kPrimitiveByte,
-    kPrimitiveChar,
-    kPrimitiveDouble,
-    kPrimitiveFloat,
-    kPrimitiveInt,
-    kPrimitiveLong,
-    kPrimitiveShort,
-    kPrimitiveVoid,
-    kBooleanArrayClass,
-    kByteArrayClass,
-    kCharArrayClass,
-    kDoubleArrayClass,
-    kFloatArrayClass,
-    kIntArrayClass,
-    kLongArrayClass,
-    kShortArrayClass,
-    kJavaLangStackTraceElementArrayClass,
-    kClassRootsMax,
-  };
+  // Well known mirror::Class roots.
   GcRoot<mirror::ObjectArray<mirror::Class>> class_roots_;
 
-  mirror::Class* GetClassRoot(ClassRoot class_root) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  void SetClassRoot(ClassRoot class_root, mirror::Class* klass)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  static const char* class_roots_descriptors_[];
-
-  const char* GetClassRootDescriptor(ClassRoot class_root) {
-    const char* descriptor = class_roots_descriptors_[class_root];
-    CHECK(descriptor != NULL);
-    return descriptor;
-  }
-
   // The interface table used by all arrays.
   GcRoot<mirror::IfTable> array_iftable_;
 
@@ -773,12 +770,11 @@
   friend class ImageWriter;  // for GetClassRoots
   friend class ImageDumper;  // for FindOpenedOatFileFromOatLocation
   friend class ElfPatcher;  // for FindOpenedOatFileForDexFile & FindOpenedOatFileFromOatLocation
+  friend class JniCompilerTest;  // for GetRuntimeQuickGenericJniStub
   friend class NoDex2OatTest;  // for FindOpenedOatFileForDexFile
   friend class NoPatchoatTest;  // for FindOpenedOatFileForDexFile
-  FRIEND_TEST(ClassLinkerTest, ClassRootDescriptors);
-  FRIEND_TEST(mirror::DexCacheTest, Open);
-  FRIEND_TEST(ExceptionTest, FindExceptionHandler);
-  FRIEND_TEST(ObjectTest, AllocObjectArray);
+  ART_FRIEND_TEST(mirror::DexCacheTest, Open);  // for AllocDexCache
+
   DISALLOW_COPY_AND_ASSIGN(ClassLinker);
 };
 
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index eed6f71..6e3ebc2 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -44,7 +44,7 @@
 
 int main(int argc, char **argv) {
   art::InitLogging(argv);
-  LOG(INFO) << "Running main() from common_runtime_test.cc...";
+  LOG(::art::INFO) << "Running main() from common_runtime_test.cc...";
   testing::InitGoogleTest(&argc, argv);
   return RUN_ALL_TESTS();
 }
@@ -185,6 +185,8 @@
   int mkdir_result = mkdir(dalvik_cache_.c_str(), 0700);
   ASSERT_EQ(mkdir_result, 0);
 
+  MemMap::Init();  // For LoadExpectSingleDexFile
+
   std::string error_msg;
   java_lang_dex_file_ = LoadExpectSingleDexFile(GetLibCoreDexFileName().c_str());
   boot_class_path_.push_back(java_lang_dex_file_);
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 6ccb53a..d9061c8 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -617,7 +617,7 @@
   VLOG(jdwp) << "ParseJdwpOptions: " << options;
 
   std::vector<std::string> pairs;
-  Split(options, ',', pairs);
+  Split(options, ',', &pairs);
 
   for (size_t i = 0; i < pairs.size(); ++i) {
     std::string::size_type equals = pairs[i].find('=');
@@ -2017,7 +2017,7 @@
   } else if (error == JDWP::ERR_NONE) {
     mirror::Class* c = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread);
     CHECK(c != nullptr);
-    mirror::ArtField* f = c->FindInstanceField("group", "Ljava/lang/ThreadGroup;");
+    mirror::ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_Thread_group);
     CHECK(f != nullptr);
     mirror::Object* group = f->GetObject(thread_object);
     CHECK(group != nullptr);
@@ -2058,8 +2058,7 @@
     return error;
   }
   ScopedAssertNoThreadSuspension ants(soa.Self(), "Debugger: GetThreadGroupName");
-  mirror::Class* c = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ThreadGroup);
-  mirror::ArtField* f = c->FindInstanceField("name", "Ljava/lang/String;");
+  mirror::ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_ThreadGroup_name);
   CHECK(f != nullptr);
   mirror::String* s = reinterpret_cast<mirror::String*>(f->GetObject(thread_group));
 
@@ -2078,9 +2077,7 @@
   mirror::Object* parent;
   {
     ScopedAssertNoThreadSuspension ants(soa.Self(), "Debugger: GetThreadGroupParent");
-    mirror::Class* c = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ThreadGroup);
-    CHECK(c != nullptr);
-    mirror::ArtField* f = c->FindInstanceField("parent", "Ljava/lang/ThreadGroup;");
+    mirror::ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_ThreadGroup_parent);
     CHECK(f != nullptr);
     parent = f->GetObject(thread_group);
   }
@@ -2095,12 +2092,20 @@
   CHECK(thread_group != nullptr);
 
   // Get the ArrayList<ThreadGroup> "groups" out of this thread group...
-  mirror::ArtField* groups_field = thread_group->GetClass()->FindInstanceField("groups", "Ljava/util/List;");
+  mirror::ArtField* groups_field = soa.DecodeField(WellKnownClasses::java_lang_ThreadGroup_groups);
   mirror::Object* groups_array_list = groups_field->GetObject(thread_group);
+  {
+    // The "groups" field is declared as a java.util.List: check it really is
+    // an instance of java.util.ArrayList.
+    CHECK(groups_array_list != nullptr);
+    mirror::Class* java_util_ArrayList_class =
+        soa.Decode<mirror::Class*>(WellKnownClasses::java_util_ArrayList);
+    CHECK(groups_array_list->InstanceOf(java_util_ArrayList_class));
+  }
 
   // Get the array and size out of the ArrayList<ThreadGroup>...
-  mirror::ArtField* array_field = groups_array_list->GetClass()->FindInstanceField("array", "[Ljava/lang/Object;");
-  mirror::ArtField* size_field = groups_array_list->GetClass()->FindInstanceField("size", "I");
+  mirror::ArtField* array_field = soa.DecodeField(WellKnownClasses::java_util_ArrayList_array);
+  mirror::ArtField* size_field = soa.DecodeField(WellKnownClasses::java_util_ArrayList_size);
   mirror::ObjectArray<mirror::Object>* groups_array =
       array_field->GetObject(groups_array_list)->AsObjectArray<mirror::Object>();
   const int32_t size = size_field->GetInt(groups_array_list);
@@ -4116,7 +4121,6 @@
   HeapChunkContext(bool merge, bool native)
       : buf_(16384 - 16),
         type_(0),
-        merge_(merge),
         chunk_overhead_(0) {
     Reset();
     if (native) {
@@ -4327,7 +4331,6 @@
   void* startOfNextMemoryChunk_;
   size_t totalAllocationUnits_;
   uint32_t type_;
-  bool merge_;
   bool needHeader_;
   size_t chunk_overhead_;
 
@@ -4678,7 +4681,7 @@
  * between the contents of these tables.
  */
 jbyteArray Dbg::GetRecentAllocations() {
-  if (false) {
+  if ((false)) {
     DumpRecentAllocations();
   }
 
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index f408386..78cbe58 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -23,7 +23,9 @@
 #include <string.h>
 #include <sys/file.h>
 #include <sys/stat.h>
+
 #include <memory>
+#include <sstream>
 
 #include "base/logging.h"
 #include "base/stringprintf.h"
diff --git a/runtime/dex_instruction.cc b/runtime/dex_instruction.cc
index 7e775f4..af38433 100644
--- a/runtime/dex_instruction.cc
+++ b/runtime/dex_instruction.cc
@@ -19,6 +19,7 @@
 #include <inttypes.h>
 
 #include <iomanip>
+#include <sstream>
 
 #include "base/stringprintf.h"
 #include "dex_file-inl.h"
diff --git a/runtime/dex_instruction_visitor_test.cc b/runtime/dex_instruction_visitor_test.cc
index c5e63eb..5273084 100644
--- a/runtime/dex_instruction_visitor_test.cc
+++ b/runtime/dex_instruction_visitor_test.cc
@@ -16,7 +16,6 @@
 
 #include "dex_instruction_visitor.h"
 
-#include <iostream>
 #include <memory>
 
 #include "gtest/gtest.h"
diff --git a/runtime/dex_method_iterator_test.cc b/runtime/dex_method_iterator_test.cc
index b8f180b..c6f333f 100644
--- a/runtime/dex_method_iterator_test.cc
+++ b/runtime/dex_method_iterator_test.cc
@@ -38,8 +38,8 @@
     const DexFile& dex_file = it.GetDexFile();
     InvokeType invoke_type = it.GetInvokeType();
     uint32_t method_idx = it.GetMemberIndex();
-    if (false) {
-      LG << invoke_type << " " << PrettyMethod(method_idx, dex_file);
+    if ((false)) {
+      LOG(INFO) << invoke_type << " " << PrettyMethod(method_idx, dex_file);
     }
     it.Next();
   }
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index c3a2559..18053c3 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -23,7 +23,10 @@
 #include "base/logging.h"
 #include "base/stringprintf.h"
 #include "base/stl_util.h"
+#include "base/unix_file/fd_file.h"
 #include "dwarf.h"
+#include "elf_file_impl.h"
+#include "elf_utils.h"
 #include "leb128.h"
 #include "utils.h"
 #include "instruction_set.h"
@@ -1661,7 +1664,7 @@
   }
 };
 
-class DebugLineInstructionIterator {
+class DebugLineInstructionIterator FINAL {
  public:
   static DebugLineInstructionIterator* Create(DebugLineHeader* header, size_t section_size) {
     std::unique_ptr<DebugLineInstructionIterator> line_iter(
@@ -1688,11 +1691,11 @@
     }
   }
 
-  uint8_t* GetInstruction() {
+  uint8_t* GetInstruction() const {
     return current_instruction_;
   }
 
-  bool IsExtendedOpcode() {
+  bool IsExtendedOpcode() const {
     return header_->IsExtendedOpcode(current_instruction_);
   }
 
@@ -1719,8 +1722,8 @@
     : header_(header), last_instruction_(reinterpret_cast<uint8_t*>(header) + size),
       current_instruction_(header->GetDebugLineData()) {}
 
-  DebugLineHeader* header_;
-  uint8_t* last_instruction_;
+  DebugLineHeader* const header_;
+  uint8_t* const last_instruction_;
   uint8_t* current_instruction_;
 };
 
@@ -1781,9 +1784,8 @@
   }
 }
 
-class DebugTag {
+class DebugTag FINAL {
  public:
-  const uint32_t index_;
   ~DebugTag() {}
   // Creates a new tag and moves data pointer up to the start of the next one.
   // nullptr means error.
@@ -1820,14 +1822,18 @@
     return size_;
   }
 
-  bool HasChild() {
+  bool HasChild() const {
     return has_child_;
   }
 
-  uint32_t GetTagNumber() {
+  uint32_t GetTagNumber() const {
     return tag_;
   }
 
+  uint32_t GetIndex() const {
+    return index_;
+  }
+
   // Gets the offset of a particular attribute in this tag structure.
   // Interpretation of the data is left to the consumer. 0 is returned if the
   // tag does not contain the attribute.
@@ -1857,6 +1863,8 @@
     size_map_.insert(std::pair<uint32_t, uint32_t>(type, attr_size));
     size_ += attr_size;
   }
+
+  const uint32_t index_;
   std::map<uint32_t, uint32_t> off_map_;
   std::map<uint32_t, uint32_t> size_map_;
   uint32_t size_;
@@ -1884,7 +1892,7 @@
       if (tag.get() == nullptr) {
         return false;
       } else {
-        tags_.insert(std::pair<uint32_t, uint32_t>(tag->index_, tag_list_.size()));
+        tags_.insert(std::pair<uint32_t, uint32_t>(tag->GetIndex(), tag_list_.size()));
         tag_list_.push_back(std::move(tag));
       }
     }
@@ -1904,8 +1912,8 @@
 
  private:
   DebugAbbrev(const uint8_t* begin, const uint8_t* end) : begin_(begin), end_(end) {}
-  const uint8_t* begin_;
-  const uint8_t* end_;
+  const uint8_t* const begin_;
+  const uint8_t* const end_;
   std::map<uint32_t, uint32_t> tags_;
   std::vector<std::unique_ptr<DebugTag>> tag_list_;
 };
@@ -1983,10 +1991,10 @@
         last_entry_(reinterpret_cast<uint8_t*>(header) + frame_size),
         current_entry_(reinterpret_cast<uint8_t*>(header) + sizeof(DebugInfoHeader)),
         current_tag_(abbrev_->ReadTag(current_entry_)) {}
-  DebugAbbrev* abbrev_;
+  DebugAbbrev* const abbrev_;
   DebugInfoHeader* current_cu_;
   DebugInfoHeader* next_cu_;
-  uint8_t* last_entry_;
+  uint8_t* const last_entry_;
   uint8_t* current_entry_;
   DebugTag* current_tag_;
 };
@@ -2406,24 +2414,15 @@
 template class ElfFileImpl<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Word,
     Elf64_Sword, Elf64_Addr, Elf64_Sym, Elf64_Rel, Elf64_Rela, Elf64_Dyn, Elf64_Off>;
 
-ElfFile::ElfFile(ElfFileImpl32* elf32) : is_elf64_(false) {
-  CHECK_NE(elf32, static_cast<ElfFileImpl32*>(nullptr));
-  elf_.elf32_ = elf32;
+ElfFile::ElfFile(ElfFileImpl32* elf32) : elf32_(elf32), elf64_(nullptr) {
 }
 
-ElfFile::ElfFile(ElfFileImpl64* elf64) : is_elf64_(true) {
-  CHECK_NE(elf64, static_cast<ElfFileImpl64*>(nullptr));
-  elf_.elf64_ = elf64;
+ElfFile::ElfFile(ElfFileImpl64* elf64) : elf32_(nullptr), elf64_(elf64) {
 }
 
 ElfFile::~ElfFile() {
-  if (is_elf64_) {
-    CHECK_NE(elf_.elf64_, static_cast<ElfFileImpl64*>(nullptr));
-    delete elf_.elf64_;
-  } else {
-    CHECK_NE(elf_.elf32_, static_cast<ElfFileImpl32*>(nullptr));
-    delete elf_.elf32_;
-  }
+  // Should never have 32 and 64-bit impls.
+  CHECK_NE(elf32_.get() == nullptr, elf64_.get() == nullptr);
 }
 
 ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only, std::string* error_msg) {
@@ -2445,8 +2444,9 @@
     return new ElfFile(elf_file_impl);
   } else if (header[EI_CLASS] == ELFCLASS32) {
     ElfFileImpl32* elf_file_impl = ElfFileImpl32::Open(file, writable, program_header_only, error_msg);
-    if (elf_file_impl == nullptr)
+    if (elf_file_impl == nullptr) {
       return nullptr;
+    }
     return new ElfFile(elf_file_impl);
   } else {
     *error_msg = StringPrintf("Failed to find expected EI_CLASS value %d or %d in %s, found %d",
@@ -2471,13 +2471,15 @@
   uint8_t* header = map->Begin();
   if (header[EI_CLASS] == ELFCLASS64) {
     ElfFileImpl64* elf_file_impl = ElfFileImpl64::Open(file, mmap_prot, mmap_flags, error_msg);
-    if (elf_file_impl == nullptr)
+    if (elf_file_impl == nullptr) {
       return nullptr;
+    }
     return new ElfFile(elf_file_impl);
   } else if (header[EI_CLASS] == ELFCLASS32) {
     ElfFileImpl32* elf_file_impl = ElfFileImpl32::Open(file, mmap_prot, mmap_flags, error_msg);
-    if (elf_file_impl == nullptr)
+    if (elf_file_impl == nullptr) {
       return nullptr;
+    }
     return new ElfFile(elf_file_impl);
   } else {
     *error_msg = StringPrintf("Failed to find expected EI_CLASS value %d or %d in %s, found %d",
@@ -2489,12 +2491,11 @@
 }
 
 #define DELEGATE_TO_IMPL(func, ...) \
-  if (is_elf64_) { \
-    CHECK_NE(elf_.elf64_, static_cast<ElfFileImpl64*>(nullptr)); \
-    return elf_.elf64_->func(__VA_ARGS__); \
+  if (elf64_.get() != nullptr) { \
+    return elf64_->func(__VA_ARGS__); \
   } else { \
-    CHECK_NE(elf_.elf32_, static_cast<ElfFileImpl32*>(nullptr)); \
-    return elf_.elf32_->func(__VA_ARGS__); \
+    DCHECK(elf32_.get() != nullptr); \
+    return elf32_->func(__VA_ARGS__); \
   }
 
 bool ElfFile::Load(bool executable, std::string* error_msg) {
@@ -2522,29 +2523,31 @@
 }
 
 bool ElfFile::GetSectionOffsetAndSize(const char* section_name, uint64_t* offset, uint64_t* size) {
-  if (is_elf64_) {
-    CHECK_NE(elf_.elf64_, static_cast<ElfFileImpl64*>(nullptr));
+  if (elf32_.get() == nullptr) {
+    CHECK(elf64_.get() != nullptr);
 
-    Elf64_Shdr *shdr = elf_.elf64_->FindSectionByName(section_name);
-    if (shdr == nullptr)
+    Elf64_Shdr *shdr = elf64_->FindSectionByName(section_name);
+    if (shdr == nullptr) {
       return false;
-
-    if (offset != nullptr)
+    }
+    if (offset != nullptr) {
       *offset = shdr->sh_offset;
-    if (size != nullptr)
+    }
+    if (size != nullptr) {
       *size = shdr->sh_size;
+    }
     return true;
   } else {
-    CHECK_NE(elf_.elf32_, static_cast<ElfFileImpl32*>(nullptr));
-
-    Elf32_Shdr *shdr = elf_.elf32_->FindSectionByName(section_name);
-    if (shdr == nullptr)
+    Elf32_Shdr *shdr = elf32_->FindSectionByName(section_name);
+    if (shdr == nullptr) {
       return false;
-
-    if (offset != nullptr)
+    }
+    if (offset != nullptr) {
       *offset = shdr->sh_offset;
-    if (size != nullptr)
+    }
+    if (size != nullptr) {
       *size = shdr->sh_size;
+    }
     return true;
   }
 }
@@ -2565,26 +2568,14 @@
     return false;
   }
 
-  if (elf_file->is_elf64_)
-    return elf_file->elf_.elf64_->Strip(error_msg);
+  if (elf_file->elf64_.get() != nullptr)
+    return elf_file->elf64_->Strip(error_msg);
   else
-    return elf_file->elf_.elf32_->Strip(error_msg);
+    return elf_file->elf32_->Strip(error_msg);
 }
 
 bool ElfFile::Fixup(uintptr_t base_address) {
   DELEGATE_TO_IMPL(Fixup, base_address);
 }
 
-ElfFileImpl32* ElfFile::GetImpl32() const {
-  CHECK(!is_elf64_);
-  CHECK_NE(elf_.elf32_, static_cast<ElfFileImpl32*>(nullptr));
-  return elf_.elf32_;
-}
-
-ElfFileImpl64* ElfFile::GetImpl64() const {
-  CHECK(is_elf64_);
-  CHECK_NE(elf_.elf64_, static_cast<ElfFileImpl64*>(nullptr));
-  return elf_.elf64_;
-}
-
 }  // namespace art
diff --git a/runtime/elf_file.h b/runtime/elf_file.h
index a7f3056..10d6360 100644
--- a/runtime/elf_file.h
+++ b/runtime/elf_file.h
@@ -17,12 +17,25 @@
 #ifndef ART_RUNTIME_ELF_FILE_H_
 #define ART_RUNTIME_ELF_FILE_H_
 
+#include <memory>
 #include <string>
 
-#include "base/unix_file/fd_file.h"
-#include "elf_file_impl.h"
+#include "base/macros.h"
+// Explicitly include our own elf.h to avoid Linux and other dependencies.
+#include "./elf.h"
+#include "os.h"
 
 namespace art {
+template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word,
+          typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel,
+          typename Elf_Rela, typename Elf_Dyn, typename Elf_Off>
+class ElfFileImpl;
+
+// Explicitly instantiated in elf_file.cc
+typedef ElfFileImpl<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Word, Elf32_Sword,
+                    Elf32_Addr, Elf32_Sym, Elf32_Rel, Elf32_Rela, Elf32_Dyn, Elf32_Off> ElfFileImpl32;
+typedef ElfFileImpl<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Word, Elf64_Sword,
+                    Elf64_Addr, Elf64_Sym, Elf64_Rel, Elf64_Rela, Elf64_Dyn, Elf64_Off> ElfFileImpl64;
 
 // Used for compile time and runtime for ElfFile access. Because of
 // the need for use at runtime, cannot directly use LLVM classes such as
@@ -35,8 +48,6 @@
   static ElfFile* Open(File* file, int mmap_prot, int mmap_flags, std::string* error_msg);
   ~ElfFile();
 
-  const bool is_elf64_;
-
   // Load segments into memory based on PT_LOAD program headers
   bool Load(bool executable, std::string* error_msg);
 
@@ -68,17 +79,26 @@
 
   bool Fixup(uintptr_t base_address);
 
-  ElfFileImpl32* GetImpl32() const;
-  ElfFileImpl64* GetImpl64() const;
+  bool Is64Bit() const {
+    return elf64_.get() != nullptr;
+  }
+
+  ElfFileImpl32* GetImpl32() const {
+    return elf32_.get();
+  }
+
+  ElfFileImpl64* GetImpl64() const {
+    return elf64_.get();
+  }
 
  private:
   explicit ElfFile(ElfFileImpl32* elf32);
   explicit ElfFile(ElfFileImpl64* elf64);
 
-  union ElfFileContainer {
-    ElfFileImpl32* elf32_;
-    ElfFileImpl64* elf64_;
-  } elf_;
+  const std::unique_ptr<ElfFileImpl32> elf32_;
+  const std::unique_ptr<ElfFileImpl64> elf64_;
+
+  DISALLOW_COPY_AND_ASSIGN(ElfFile);
 };
 
 }  // namespace art
diff --git a/runtime/elf_file_impl.h b/runtime/elf_file_impl.h
index a2fc422..a8bb465 100644
--- a/runtime/elf_file_impl.h
+++ b/runtime/elf_file_impl.h
@@ -21,11 +21,9 @@
 #include <memory>
 #include <vector>
 
-#include "base/unix_file/fd_file.h"
-#include "globals.h"
-#include "elf_utils.h"
+// Explicitly include our own elf.h to avoid Linux and other dependencies.
+#include "./elf.h"
 #include "mem_map.h"
-#include "os.h"
 
 namespace art {
 
@@ -207,13 +205,9 @@
                   Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel,
                   Elf_Rela, Elf_Dyn, Elf_Off>> gdb_file_mapping_;
   void GdbJITSupport();
-};
 
-// Explicitly instantiated in elf_file.cc
-typedef ElfFileImpl<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Word, Elf32_Sword,
-                    Elf32_Addr, Elf32_Sym, Elf32_Rel, Elf32_Rela, Elf32_Dyn, Elf32_Off> ElfFileImpl32;
-typedef ElfFileImpl<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Word, Elf64_Sword,
-                    Elf64_Addr, Elf64_Sym, Elf64_Rel, Elf64_Rela, Elf64_Dyn, Elf64_Off> ElfFileImpl64;
+  DISALLOW_COPY_AND_ASSIGN(ElfFileImpl);
+};
 
 }  // namespace art
 
diff --git a/runtime/elf_utils.h b/runtime/elf_utils.h
index 5966d05..7b00bad 100644
--- a/runtime/elf_utils.h
+++ b/runtime/elf_utils.h
@@ -24,6 +24,8 @@
 
 #include "base/logging.h"
 
+namespace art {
+
 // Architecture dependent flags for the ELF header.
 #define EF_ARM_EABI_VER5 0x05000000
 #define EF_MIPS_ABI_O32 0x00001000
@@ -67,11 +69,11 @@
 // Patching section type
 #define SHT_OAT_PATCH        SHT_LOUSER
 
-inline void SetBindingAndType(Elf32_Sym* sym, unsigned char b, unsigned char t) {
+static inline void SetBindingAndType(Elf32_Sym* sym, unsigned char b, unsigned char t) {
   sym->st_info = (b << 4) + (t & 0x0f);
 }
 
-inline bool IsDynamicSectionPointer(Elf32_Word d_tag, Elf32_Word e_machine) {
+static inline bool IsDynamicSectionPointer(Elf32_Word d_tag, Elf32_Word e_machine) {
   switch (d_tag) {
     // case 1: well known d_tag values that imply Elf32_Dyn.d_un contains an address in d_ptr
     case DT_PLTGOT:
@@ -163,4 +165,6 @@
   }
 }
 
+}  // namespace art
+
 #endif  // ART_RUNTIME_ELF_UTILS_H_
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index ce34993..c46d887 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -183,59 +183,6 @@
 bool FillArrayData(mirror::Object* obj, const Instruction::ArrayDataPayload* payload)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-// Entry point for deoptimization.
-extern "C" void art_quick_deoptimize();
-static inline uintptr_t GetQuickDeoptimizationEntryPoint() {
-  return reinterpret_cast<uintptr_t>(art_quick_deoptimize);
-}
-
-// Return address of instrumentation stub.
-extern "C" void art_quick_instrumentation_entry(void*);
-static inline void* GetQuickInstrumentationEntryPoint() {
-  return reinterpret_cast<void*>(art_quick_instrumentation_entry);
-}
-
-// The return_pc of instrumentation exit stub.
-extern "C" void art_quick_instrumentation_exit();
-static inline uintptr_t GetQuickInstrumentationExitPc() {
-  return reinterpret_cast<uintptr_t>(art_quick_instrumentation_exit);
-}
-
-extern "C" void art_portable_to_interpreter_bridge(mirror::ArtMethod*);
-static inline const void* GetPortableToInterpreterBridge() {
-  return reinterpret_cast<void*>(art_portable_to_interpreter_bridge);
-}
-
-static inline const void* GetPortableToQuickBridge() {
-  // TODO: portable to quick bridge. Bug: 8196384
-  return GetPortableToInterpreterBridge();
-}
-
-extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*);
-static inline const void* GetQuickToInterpreterBridge() {
-  return reinterpret_cast<void*>(art_quick_to_interpreter_bridge);
-}
-
-static inline const void* GetQuickToPortableBridge() {
-  // TODO: quick to portable bridge. Bug: 8196384
-  return GetQuickToInterpreterBridge();
-}
-
-extern "C" void art_portable_proxy_invoke_handler();
-static inline const void* GetPortableProxyInvokeHandler() {
-  return reinterpret_cast<void*>(art_portable_proxy_invoke_handler);
-}
-
-extern "C" void art_quick_proxy_invoke_handler();
-static inline const void* GetQuickProxyInvokeHandler() {
-  return reinterpret_cast<void*>(art_quick_proxy_invoke_handler);
-}
-
-extern "C" void* art_jni_dlsym_lookup_stub(JNIEnv*, jobject);
-static inline void* GetJniDlsymLookupStub() {
-  return reinterpret_cast<void*>(art_jni_dlsym_lookup_stub);
-}
-
 template <typename INT_TYPE, typename FLOAT_TYPE>
 static inline INT_TYPE art_float_to_integral(FLOAT_TYPE f);
 
diff --git a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
index b617636..908d3cd 100644
--- a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
+++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
@@ -25,7 +25,7 @@
 namespace art {
 
 // TODO: Make the MethodHelper here be compaction safe.
-extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh,
+extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper* mh,
                                                    const DexFile::CodeItem* code_item,
                                                    ShadowFrame* shadow_frame, JValue* result) {
   mirror::ArtMethod* method = shadow_frame->GetMethod();
@@ -54,7 +54,7 @@
   } else {
     method->Invoke(self, shadow_frame->GetVRegArgs(arg_offset),
                    (shadow_frame->NumberOfVRegs() - arg_offset) * sizeof(uint32_t),
-                   result, mh.GetShorty());
+                   result, mh->GetShorty());
   }
 }
 
diff --git a/runtime/entrypoints/interpreter/interpreter_entrypoints.h b/runtime/entrypoints/interpreter/interpreter_entrypoints.h
index d8b2204..5d646e9 100644
--- a/runtime/entrypoints/interpreter/interpreter_entrypoints.h
+++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.h
@@ -33,10 +33,10 @@
 
 // Pointers to functions that are called by interpreter trampolines via thread-local storage.
 struct PACKED(4) InterpreterEntryPoints {
-  void (*pInterpreterToInterpreterBridge)(Thread* self, MethodHelper& mh,
+  void (*pInterpreterToInterpreterBridge)(Thread* self, MethodHelper* mh,
                                           const DexFile::CodeItem* code_item,
                                           ShadowFrame* shadow_frame, JValue* result);
-  void (*pInterpreterToCompiledCodeBridge)(Thread* self, MethodHelper& mh,
+  void (*pInterpreterToCompiledCodeBridge)(Thread* self, MethodHelper* mh,
                                            const DexFile::CodeItem* code_item,
                                            ShadowFrame* shadow_frame, JValue* result);
 };
diff --git a/runtime/entrypoints/jni/jni_entrypoints.cc b/runtime/entrypoints/jni/jni_entrypoints.cc
index edb3b72..2752407 100644
--- a/runtime/entrypoints/jni/jni_entrypoints.cc
+++ b/runtime/entrypoints/jni/jni_entrypoints.cc
@@ -45,7 +45,7 @@
     return NULL;
   } else {
     // Register so that future calls don't come here
-    method->RegisterNative(self, native_code, false);
+    method->RegisterNative(native_code, false);
     return native_code;
   }
 }
diff --git a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
index 642c94a..c3664bf 100644
--- a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
@@ -19,6 +19,7 @@
 
 #include "dex_instruction-inl.h"
 #include "entrypoints/entrypoint_utils-inl.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
 #include "interpreter/interpreter.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/object-inl.h"
@@ -222,7 +223,7 @@
       }
     }
 
-    JValue result = interpreter::EnterInterpreterFromStub(self, mh, code_item, *shadow_frame);
+    JValue result = interpreter::EnterInterpreterFromEntryPoint(self, &mh, code_item, shadow_frame);
     // Pop transition.
     self->PopManagedStackFragment(fragment);
     return result.GetJ();
@@ -323,7 +324,7 @@
   uint32_t dex_pc;
   mirror::ArtMethod* caller = self->GetCurrentMethod(&dex_pc);
 
-  ClassLinker* linker = Runtime::Current()->GetClassLinker();
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   InvokeType invoke_type;
   bool is_range;
   if (called->IsRuntimeMethod()) {
@@ -379,7 +380,7 @@
         is_range = true;
     }
     uint32_t dex_method_idx = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c();
-    called = linker->ResolveMethod(Thread::Current(), dex_method_idx, &caller, invoke_type);
+    called = class_linker->ResolveMethod(Thread::Current(), dex_method_idx, &caller, invoke_type);
     // Incompatible class change should have been handled in resolve method.
     CHECK(!called->CheckIncompatibleClassChange(invoke_type));
     // Refine called method based on receiver.
@@ -399,27 +400,27 @@
     // Ensure that the called method's class is initialized.
     StackHandleScope<1> hs(self);
     Handle<mirror::Class> called_class(hs.NewHandle(called->GetDeclaringClass()));
-    linker->EnsureInitialized(self, called_class, true, true);
+    class_linker->EnsureInitialized(self, called_class, true, true);
     if (LIKELY(called_class->IsInitialized())) {
       code = called->GetEntryPointFromPortableCompiledCode();
       // TODO: remove this after we solve the link issue.
       if (code == nullptr) {
         bool have_portable_code;
-        code = linker->GetPortableOatCodeFor(called, &have_portable_code);
+        code = class_linker->GetPortableOatCodeFor(called, &have_portable_code);
       }
     } else if (called_class->IsInitializing()) {
       if (invoke_type == kStatic) {
         // Class is still initializing, go to oat and grab code (trampoline must be left in place
         // until class is initialized to stop races between threads).
         bool have_portable_code;
-        code = linker->GetPortableOatCodeFor(called, &have_portable_code);
+        code = class_linker->GetPortableOatCodeFor(called, &have_portable_code);
       } else {
         // No trampoline for non-static methods.
         code = called->GetEntryPointFromPortableCompiledCode();
         // TODO: remove this after we solve the link issue.
         if (code == nullptr) {
           bool have_portable_code;
-          code = linker->GetPortableOatCodeFor(called, &have_portable_code);
+          code = class_linker->GetPortableOatCodeFor(called, &have_portable_code);
         }
       }
     } else {
@@ -430,7 +431,7 @@
     // Expect class to at least be initializing.
     DCHECK(called->GetDeclaringClass()->IsInitializing());
     // Don't want infinite recursion.
-    DCHECK(code != linker->GetPortableResolutionTrampoline());
+    DCHECK(!class_linker->IsPortableResolutionStub(code));
     // Set up entry into main method
     *called_addr = called;
   }
diff --git a/runtime/entrypoints/quick/callee_save_frame.h b/runtime/entrypoints/quick/callee_save_frame.h
index e728f7d..49357ad 100644
--- a/runtime/entrypoints/quick/callee_save_frame.h
+++ b/runtime/entrypoints/quick/callee_save_frame.h
@@ -18,9 +18,8 @@
 #define ART_RUNTIME_ENTRYPOINTS_QUICK_CALLEE_SAVE_FRAME_H_
 
 #include "base/mutex.h"
-#include "gc_root-inl.h"
 #include "instruction_set.h"
-#include "runtime-inl.h"
+#include "runtime.h"
 #include "thread-inl.h"
 
 // Specific frame size code is in architecture-specific files. We include this to compile-time
@@ -36,16 +35,41 @@
 class ArtMethod;
 }  // namespace mirror
 
-// Place a special frame at the TOS that will save the callee saves for the given type.
-static inline void FinishCalleeSaveFrameSetup(Thread* self, StackReference<mirror::ArtMethod>* sp,
-                                              Runtime::CalleeSaveType type)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  // Be aware the store below may well stomp on an incoming argument.
-  Locks::mutator_lock_->AssertSharedHeld(self);
-  sp->Assign(Runtime::Current()->GetCalleeSaveMethod(type));
-  self->SetTopOfStack(sp, 0);
-  self->VerifyStack();
-}
+class ScopedQuickEntrypointChecks {
+ public:
+  explicit ScopedQuickEntrypointChecks(Thread *self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : self_(self) {
+    if (kIsDebugBuild) {
+      TestsOnEntry();
+    }
+  }
+
+  explicit ScopedQuickEntrypointChecks() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : self_(kIsDebugBuild ? Thread::Current() : nullptr) {
+    if (kIsDebugBuild) {
+      TestsOnEntry();
+    }
+  }
+
+  ~ScopedQuickEntrypointChecks() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    if (kIsDebugBuild) {
+      TestsOnExit();
+    }
+  }
+
+ private:
+  void TestsOnEntry() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    Locks::mutator_lock_->AssertSharedHeld(self_);
+    self_->VerifyStack();
+  }
+
+  void TestsOnExit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    Locks::mutator_lock_->AssertSharedHeld(self_);
+    self_->VerifyStack();
+  }
+
+  Thread* const self_;
+};
 
 static constexpr size_t GetCalleeSaveFrameSize(InstructionSet isa, Runtime::CalleeSaveType type) {
   // constexpr must be a return statement.
@@ -71,7 +95,8 @@
 }
 
 // Note: this specialized statement is sanity-checked in the quick-trampoline gtest.
-static constexpr size_t GetCalleeSavePCOffset(InstructionSet isa, Runtime::CalleeSaveType type) {
+static constexpr size_t GetCalleeSaveReturnPcOffset(InstructionSet isa,
+                                                    Runtime::CalleeSaveType type) {
   return GetCalleeSaveFrameSize(isa, type) - GetConstExprPointerSize(isa);
 }
 
diff --git a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
index d8da463..a2869ec 100644
--- a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
@@ -32,6 +32,7 @@
     uint32_t type_idx, mirror::ArtMethod* method, Thread* self, \
     StackReference<mirror::ArtMethod>* sp) \
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { \
+  ScopedQuickEntrypointChecks sqec(self); \
   if (kUseTlabFastPath && !instrumented_bool && allocator_type == gc::kAllocatorTypeTLAB) { \
     mirror::Class* klass = method->GetDexCacheResolvedType<false>(type_idx); \
     if (LIKELY(klass != nullptr && klass->IsInitialized() && !klass->IsFinalizable())) { \
@@ -53,13 +54,12 @@
       } \
     } \
   } \
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); \
   return AllocObjectFromCode<false, instrumented_bool>(type_idx, method, self, allocator_type); \
 } \
 extern "C" mirror::Object* artAllocObjectFromCodeResolved##suffix##suffix2( \
-    mirror::Class* klass, mirror::ArtMethod* method, Thread* self, \
-    StackReference<mirror::ArtMethod>* sp) \
+    mirror::Class* klass, mirror::ArtMethod* method, Thread* self) \
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { \
+  ScopedQuickEntrypointChecks sqec(self); \
   if (kUseTlabFastPath && !instrumented_bool && allocator_type == gc::kAllocatorTypeTLAB) { \
     if (LIKELY(klass->IsInitialized())) { \
       size_t byte_count = klass->GetObjectSize(); \
@@ -80,13 +80,12 @@
       } \
     } \
   } \
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); \
   return AllocObjectFromCodeResolved<instrumented_bool>(klass, method, self, allocator_type); \
 } \
 extern "C" mirror::Object* artAllocObjectFromCodeInitialized##suffix##suffix2( \
-    mirror::Class* klass, mirror::ArtMethod* method, Thread* self, \
-    StackReference<mirror::ArtMethod>* sp) \
+    mirror::Class* klass, mirror::ArtMethod* method, Thread* self) \
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { \
+  ScopedQuickEntrypointChecks sqec(self); \
   if (kUseTlabFastPath && !instrumented_bool && allocator_type == gc::kAllocatorTypeTLAB) { \
     size_t byte_count = klass->GetObjectSize(); \
     byte_count = RoundUp(byte_count, gc::space::BumpPointerSpace::kAlignment); \
@@ -105,45 +104,39 @@
       return obj; \
     } \
   } \
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); \
   return AllocObjectFromCodeInitialized<instrumented_bool>(klass, method, self, allocator_type); \
 } \
 extern "C" mirror::Object* artAllocObjectFromCodeWithAccessCheck##suffix##suffix2( \
-    uint32_t type_idx, mirror::ArtMethod* method, Thread* self, \
-    StackReference<mirror::ArtMethod>* sp) \
+    uint32_t type_idx, mirror::ArtMethod* method, Thread* self) \
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { \
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); \
+  ScopedQuickEntrypointChecks sqec(self); \
   return AllocObjectFromCode<true, instrumented_bool>(type_idx, method, self, allocator_type); \
 } \
 extern "C" mirror::Array* artAllocArrayFromCode##suffix##suffix2( \
-    uint32_t type_idx, mirror::ArtMethod* method, int32_t component_count, Thread* self, \
-    StackReference<mirror::ArtMethod>* sp) \
+    uint32_t type_idx, mirror::ArtMethod* method, int32_t component_count, Thread* self) \
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { \
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); \
+  ScopedQuickEntrypointChecks sqec(self); \
   return AllocArrayFromCode<false, instrumented_bool>(type_idx, method, component_count, self, \
                                                       allocator_type); \
 } \
 extern "C" mirror::Array* artAllocArrayFromCodeResolved##suffix##suffix2( \
-    mirror::Class* klass, mirror::ArtMethod* method, int32_t component_count, Thread* self, \
-    StackReference<mirror::ArtMethod>* sp) \
+    mirror::Class* klass, mirror::ArtMethod* method, int32_t component_count, Thread* self) \
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { \
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); \
+  ScopedQuickEntrypointChecks sqec(self); \
   return AllocArrayFromCodeResolved<false, instrumented_bool>(klass, method, component_count, self, \
                                                               allocator_type); \
 } \
 extern "C" mirror::Array* artAllocArrayFromCodeWithAccessCheck##suffix##suffix2( \
-    uint32_t type_idx, mirror::ArtMethod* method, int32_t component_count, Thread* self, \
-    StackReference<mirror::ArtMethod>* sp) \
+    uint32_t type_idx, mirror::ArtMethod* method, int32_t component_count, Thread* self) \
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { \
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); \
+  ScopedQuickEntrypointChecks sqec(self); \
   return AllocArrayFromCode<true, instrumented_bool>(type_idx, method, component_count, self, \
                                                      allocator_type); \
 } \
 extern "C" mirror::Array* artCheckAndAllocArrayFromCode##suffix##suffix2( \
-    uint32_t type_idx, mirror::ArtMethod* method, int32_t component_count, Thread* self, \
-    StackReference<mirror::ArtMethod>* sp) \
+    uint32_t type_idx, mirror::ArtMethod* method, int32_t component_count, Thread* self) \
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { \
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); \
+  ScopedQuickEntrypointChecks sqec(self); \
   if (!instrumented_bool) { \
     return CheckAndAllocArrayFromCode(type_idx, method, component_count, self, false, allocator_type); \
   } else { \
@@ -151,10 +144,9 @@
   } \
 } \
 extern "C" mirror::Array* artCheckAndAllocArrayFromCodeWithAccessCheck##suffix##suffix2( \
-    uint32_t type_idx, mirror::ArtMethod* method, int32_t component_count, Thread* self, \
-    StackReference<mirror::ArtMethod>* sp) \
+    uint32_t type_idx, mirror::ArtMethod* method, int32_t component_count, Thread* self) \
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { \
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); \
+  ScopedQuickEntrypointChecks sqec(self); \
   if (!instrumented_bool) { \
     return CheckAndAllocArrayFromCode(type_idx, method, component_count, self, true, allocator_type); \
   } else { \
diff --git a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
index f9f62c2..14ab320 100644
--- a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
@@ -27,9 +27,8 @@
 
 namespace art {
 
-extern "C" void artDeoptimize(Thread* self, StackReference<mirror::ArtMethod>* sp)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
+extern "C" void artDeoptimize(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   self->SetException(ThrowLocation(), Thread::GetDeoptimizationException());
   self->QuickDeliverException();
 }
diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
index 704db05..2e7c8ba 100644
--- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
@@ -27,42 +27,39 @@
 
 extern "C" mirror::Class* artInitializeStaticStorageFromCode(uint32_t type_idx,
                                                              mirror::ArtMethod* referrer,
-                                                             Thread* self,
-                                                             StackReference<mirror::ArtMethod>* sp)
+                                                             Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // Called to ensure static storage base is initialized for direct static field reads and writes.
   // A class may be accessing another class' fields when it doesn't have access, as access has been
   // given by inheritance.
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+  ScopedQuickEntrypointChecks sqec(self);
   return ResolveVerifyAndClinit(type_idx, referrer, self, true, false);
 }
 
 extern "C" mirror::Class* artInitializeTypeFromCode(uint32_t type_idx,
                                                     mirror::ArtMethod* referrer,
-                                                    Thread* self,
-                                                    StackReference<mirror::ArtMethod>* sp)
+                                                    Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // Called when method->dex_cache_resolved_types_[] misses.
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+  ScopedQuickEntrypointChecks sqec(self);
   return ResolveVerifyAndClinit(type_idx, referrer, self, false, false);
 }
 
 extern "C" mirror::Class* artInitializeTypeAndVerifyAccessFromCode(uint32_t type_idx,
-    mirror::ArtMethod* referrer,
-    Thread* self,
-    StackReference<mirror::ArtMethod>* sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+                                                                   mirror::ArtMethod* referrer,
+                                                                   Thread* self)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // Called when caller isn't guaranteed to have access to a type and the dex cache may be
   // unpopulated.
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+  ScopedQuickEntrypointChecks sqec(self);
   return ResolveVerifyAndClinit(type_idx, referrer, self, false, true);
 }
 
 extern "C" mirror::String* artResolveStringFromCode(mirror::ArtMethod* referrer,
                                                     int32_t string_idx,
-                                                    Thread* self,
-                                                    StackReference<mirror::ArtMethod>* sp)
+                                                    Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+  ScopedQuickEntrypointChecks sqec(self);
   return ResolveStringFromCode(referrer, string_idx);
 }
 
diff --git a/runtime/entrypoints/quick/quick_field_entrypoints.cc b/runtime/entrypoints/quick/quick_field_entrypoints.cc
index b89c015..7326fcf 100644
--- a/runtime/entrypoints/quick/quick_field_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_field_entrypoints.cc
@@ -25,295 +25,284 @@
 
 namespace art {
 
-extern "C" int8_t artGetByteStaticFromCode(uint32_t field_idx,
-                                           mirror::ArtMethod* referrer,
-                                           Thread* self, StackReference<mirror::ArtMethod>* sp)
+extern "C" int8_t artGetByteStaticFromCode(uint32_t field_idx, mirror::ArtMethod* referrer,
+                                           Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead,
                                           sizeof(int8_t));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     return field->GetByte(field->GetDeclaringClass());
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode<StaticPrimitiveRead, true>(field_idx, referrer, self, sizeof(int8_t));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     return field->GetByte(field->GetDeclaringClass());
   }
-  return 0;  // Will throw exception by checking with Thread::Current
+  return 0;  // Will throw exception by checking with Thread::Current.
 }
 
-extern "C" uint8_t artGetBooleanStaticFromCode(uint32_t field_idx,
-                                               mirror::ArtMethod* referrer,
-                                               Thread* self, StackReference<mirror::ArtMethod>* sp)
+extern "C" uint8_t artGetBooleanStaticFromCode(uint32_t field_idx, mirror::ArtMethod* referrer,
+                                               Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead,
                                           sizeof(int8_t));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     return field->GetBoolean(field->GetDeclaringClass());
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode<StaticPrimitiveRead, true>(field_idx, referrer, self, sizeof(int8_t));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     return field->GetBoolean(field->GetDeclaringClass());
   }
-  return 0;  // Will throw exception by checking with Thread::Current
+  return 0;  // Will throw exception by checking with Thread::Current.
 }
 
-extern "C" int16_t artGetShortStaticFromCode(uint32_t field_idx,
-                                             mirror::ArtMethod* referrer,
-                                             Thread* self, StackReference<mirror::ArtMethod>* sp)
+extern "C" int16_t artGetShortStaticFromCode(uint32_t field_idx, mirror::ArtMethod* referrer,
+                                             Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead,
                                           sizeof(int16_t));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     return field->GetShort(field->GetDeclaringClass());
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode<StaticPrimitiveRead, true>(field_idx, referrer, self, sizeof(int16_t));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     return field->GetShort(field->GetDeclaringClass());
   }
-  return 0;  // Will throw exception by checking with Thread::Current
+  return 0;  // Will throw exception by checking with Thread::Current.
 }
 
 extern "C" uint16_t artGetCharStaticFromCode(uint32_t field_idx,
                                              mirror::ArtMethod* referrer,
-                                             Thread* self, StackReference<mirror::ArtMethod>* sp)
+                                             Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead,
                                           sizeof(int16_t));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     return field->GetChar(field->GetDeclaringClass());
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode<StaticPrimitiveRead, true>(field_idx, referrer, self, sizeof(int16_t));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     return field->GetChar(field->GetDeclaringClass());
   }
-  return 0;  // Will throw exception by checking with Thread::Current
+  return 0;  // Will throw exception by checking with Thread::Current.
 }
 
 extern "C" uint32_t artGet32StaticFromCode(uint32_t field_idx,
                                            mirror::ArtMethod* referrer,
-                                           Thread* self, StackReference<mirror::ArtMethod>* sp)
+                                           Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead,
                                           sizeof(int32_t));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     return field->Get32(field->GetDeclaringClass());
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode<StaticPrimitiveRead, true>(field_idx, referrer, self, sizeof(int32_t));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     return field->Get32(field->GetDeclaringClass());
   }
-  return 0;  // Will throw exception by checking with Thread::Current
+  return 0;  // Will throw exception by checking with Thread::Current.
 }
 
 extern "C" uint64_t artGet64StaticFromCode(uint32_t field_idx,
                                            mirror::ArtMethod* referrer,
-                                           Thread* self, StackReference<mirror::ArtMethod>* sp)
+                                           Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead,
                                           sizeof(int64_t));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     return field->Get64(field->GetDeclaringClass());
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode<StaticPrimitiveRead, true>(field_idx, referrer, self, sizeof(int64_t));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     return field->Get64(field->GetDeclaringClass());
   }
-  return 0;  // Will throw exception by checking with Thread::Current
+  return 0;  // Will throw exception by checking with Thread::Current.
 }
 
 extern "C" mirror::Object* artGetObjStaticFromCode(uint32_t field_idx,
                                                    mirror::ArtMethod* referrer,
-                                                   Thread* self,
-                                                   StackReference<mirror::ArtMethod>* sp)
+                                                   Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticObjectRead,
                                           sizeof(mirror::HeapReference<mirror::Object>));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     return field->GetObj(field->GetDeclaringClass());
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode<StaticObjectRead, true>(field_idx, referrer, self,
                                                     sizeof(mirror::HeapReference<mirror::Object>));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     return field->GetObj(field->GetDeclaringClass());
   }
-  return NULL;  // Will throw exception by checking with Thread::Current
+  return nullptr;  // Will throw exception by checking with Thread::Current.
 }
 
 extern "C" int8_t artGetByteInstanceFromCode(uint32_t field_idx, mirror::Object* obj,
-                                             mirror::ArtMethod* referrer, Thread* self,
-                                             StackReference<mirror::ArtMethod>* sp)
+                                             mirror::ArtMethod* referrer, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead,
                                           sizeof(int8_t));
-  if (LIKELY(field != NULL && obj != NULL)) {
+  if (LIKELY(field != nullptr && obj != nullptr)) {
     return field->GetByte(obj);
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode<InstancePrimitiveRead, true>(field_idx, referrer, self,
                                                          sizeof(int8_t));
-  if (LIKELY(field != NULL)) {
-    if (UNLIKELY(obj == NULL)) {
+  if (LIKELY(field != nullptr)) {
+    if (UNLIKELY(obj == nullptr)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
       ThrowNullPointerExceptionForFieldAccess(throw_location, field, true);
     } else {
       return field->GetByte(obj);
     }
   }
-  return 0;  // Will throw exception by checking with Thread::Current
+  return 0;  // Will throw exception by checking with Thread::Current.
 }
 
 extern "C" uint8_t artGetBooleanInstanceFromCode(uint32_t field_idx, mirror::Object* obj,
-                                                 mirror::ArtMethod* referrer, Thread* self,
-                                                 StackReference<mirror::ArtMethod>* sp)
+                                                 mirror::ArtMethod* referrer, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead,
                                           sizeof(int8_t));
-  if (LIKELY(field != NULL && obj != NULL)) {
+  if (LIKELY(field != nullptr && obj != nullptr)) {
     return field->GetBoolean(obj);
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode<InstancePrimitiveRead, true>(field_idx, referrer, self,
                                                          sizeof(int8_t));
-  if (LIKELY(field != NULL)) {
-    if (UNLIKELY(obj == NULL)) {
+  if (LIKELY(field != nullptr)) {
+    if (UNLIKELY(obj == nullptr)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
       ThrowNullPointerExceptionForFieldAccess(throw_location, field, true);
     } else {
       return field->GetBoolean(obj);
     }
   }
-  return 0;  // Will throw exception by checking with Thread::Current
+  return 0;  // Will throw exception by checking with Thread::Current.
 }
 extern "C" int16_t artGetShortInstanceFromCode(uint32_t field_idx, mirror::Object* obj,
-                                               mirror::ArtMethod* referrer, Thread* self,
-                                               StackReference<mirror::ArtMethod>* sp)
+                                               mirror::ArtMethod* referrer, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead,
                                           sizeof(int16_t));
-  if (LIKELY(field != NULL && obj != NULL)) {
+  if (LIKELY(field != nullptr && obj != nullptr)) {
     return field->GetShort(obj);
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode<InstancePrimitiveRead, true>(field_idx, referrer, self,
                                                          sizeof(int16_t));
-  if (LIKELY(field != NULL)) {
-    if (UNLIKELY(obj == NULL)) {
+  if (LIKELY(field != nullptr)) {
+    if (UNLIKELY(obj == nullptr)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
       ThrowNullPointerExceptionForFieldAccess(throw_location, field, true);
     } else {
       return field->GetShort(obj);
     }
   }
-  return 0;  // Will throw exception by checking with Thread::Current
+  return 0;  // Will throw exception by checking with Thread::Current.
 }
 
 extern "C" uint16_t artGetCharInstanceFromCode(uint32_t field_idx, mirror::Object* obj,
-                                               mirror::ArtMethod* referrer, Thread* self,
-                                               StackReference<mirror::ArtMethod>* sp)
+                                               mirror::ArtMethod* referrer, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead,
                                           sizeof(int16_t));
-  if (LIKELY(field != NULL && obj != NULL)) {
+  if (LIKELY(field != nullptr && obj != nullptr)) {
     return field->GetChar(obj);
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode<InstancePrimitiveRead, true>(field_idx, referrer, self,
                                                          sizeof(int16_t));
-  if (LIKELY(field != NULL)) {
-    if (UNLIKELY(obj == NULL)) {
+  if (LIKELY(field != nullptr)) {
+    if (UNLIKELY(obj == nullptr)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
       ThrowNullPointerExceptionForFieldAccess(throw_location, field, true);
     } else {
       return field->GetChar(obj);
     }
   }
-  return 0;  // Will throw exception by checking with Thread::Current
+  return 0;  // Will throw exception by checking with Thread::Current.
 }
 
 extern "C" uint32_t artGet32InstanceFromCode(uint32_t field_idx, mirror::Object* obj,
-                                             mirror::ArtMethod* referrer, Thread* self,
-                                             StackReference<mirror::ArtMethod>* sp)
+                                             mirror::ArtMethod* referrer, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead,
                                           sizeof(int32_t));
-  if (LIKELY(field != NULL && obj != NULL)) {
+  if (LIKELY(field != nullptr && obj != nullptr)) {
     return field->Get32(obj);
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode<InstancePrimitiveRead, true>(field_idx, referrer, self,
                                                          sizeof(int32_t));
-  if (LIKELY(field != NULL)) {
-    if (UNLIKELY(obj == NULL)) {
+  if (LIKELY(field != nullptr)) {
+    if (UNLIKELY(obj == nullptr)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
       ThrowNullPointerExceptionForFieldAccess(throw_location, field, true);
     } else {
       return field->Get32(obj);
     }
   }
-  return 0;  // Will throw exception by checking with Thread::Current
+  return 0;  // Will throw exception by checking with Thread::Current.
 }
 
 extern "C" uint64_t artGet64InstanceFromCode(uint32_t field_idx, mirror::Object* obj,
-                                             mirror::ArtMethod* referrer, Thread* self,
-                                             StackReference<mirror::ArtMethod>* sp)
+                                             mirror::ArtMethod* referrer, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead,
                                           sizeof(int64_t));
-  if (LIKELY(field != NULL && obj != NULL)) {
+  if (LIKELY(field != nullptr && obj != nullptr)) {
     return field->Get64(obj);
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode<InstancePrimitiveRead, true>(field_idx, referrer, self,
                                                          sizeof(int64_t));
-  if (LIKELY(field != NULL)) {
-    if (UNLIKELY(obj == NULL)) {
+  if (LIKELY(field != nullptr)) {
+    if (UNLIKELY(obj == nullptr)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
       ThrowNullPointerExceptionForFieldAccess(throw_location, field, true);
     } else {
       return field->Get64(obj);
     }
   }
-  return 0;  // Will throw exception by checking with Thread::Current
+  return 0;  // Will throw exception by checking with Thread::Current.
 }
 
 extern "C" mirror::Object* artGetObjInstanceFromCode(uint32_t field_idx, mirror::Object* obj,
                                                      mirror::ArtMethod* referrer,
-                                                     Thread* self,
-                                                     StackReference<mirror::ArtMethod>* sp)
+                                                     Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectRead,
                                           sizeof(mirror::HeapReference<mirror::Object>));
-  if (LIKELY(field != NULL && obj != NULL)) {
+  if (LIKELY(field != nullptr && obj != nullptr)) {
     return field->GetObj(obj);
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode<InstanceObjectRead, true>(field_idx, referrer, self,
                                                       sizeof(mirror::HeapReference<mirror::Object>));
-  if (LIKELY(field != NULL)) {
-    if (UNLIKELY(obj == NULL)) {
+  if (LIKELY(field != nullptr)) {
+    if (UNLIKELY(obj == nullptr)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
       ThrowNullPointerExceptionForFieldAccess(throw_location, field, true);
     } else {
       return field->GetObj(obj);
     }
   }
-  return NULL;  // Will throw exception by checking with Thread::Current
+  return nullptr;  // Will throw exception by checking with Thread::Current.
 }
 
 extern "C" int artSet8StaticFromCode(uint32_t field_idx, uint32_t new_value,
-                                     mirror::ArtMethod* referrer, Thread* self,
-                                     StackReference<mirror::ArtMethod>* sp)
+                                     mirror::ArtMethod* referrer, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite,
                                           sizeof(int8_t));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     Primitive::Type type = field->GetTypeAsPrimitiveType();
     // Compiled code can't use transactional mode.
     if (type == Primitive::kPrimBoolean) {
@@ -324,9 +313,8 @@
     }
     return 0;  // success
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, self, sizeof(int8_t));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     Primitive::Type type = field->GetTypeAsPrimitiveType();
     // Compiled code can't use transactional mode.
     if (type == Primitive::kPrimBoolean) {
@@ -341,12 +329,12 @@
 }
 
 extern "C" int artSet16StaticFromCode(uint32_t field_idx, uint16_t new_value,
-                                      mirror::ArtMethod* referrer, Thread* self,
-                                      StackReference<mirror::ArtMethod>* sp)
+                                      mirror::ArtMethod* referrer, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite,
                                           sizeof(int16_t));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     Primitive::Type type = field->GetTypeAsPrimitiveType();
     // Compiled code can't use transactional mode.
     if (type == Primitive::kPrimChar) {
@@ -357,9 +345,8 @@
     }
     return 0;  // success
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, self, sizeof(int16_t));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     Primitive::Type type = field->GetTypeAsPrimitiveType();
     // Compiled code can't use transactional mode.
     if (type == Primitive::kPrimChar) {
@@ -374,19 +361,18 @@
 }
 
 extern "C" int artSet32StaticFromCode(uint32_t field_idx, uint32_t new_value,
-                                      mirror::ArtMethod* referrer, Thread* self,
-                                      StackReference<mirror::ArtMethod>* sp)
+                                      mirror::ArtMethod* referrer, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite,
                                           sizeof(int32_t));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     // Compiled code can't use transactional mode.
     field->Set32<false>(field->GetDeclaringClass(), new_value);
     return 0;  // success
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, self, sizeof(int32_t));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     // Compiled code can't use transactional mode.
     field->Set32<false>(field->GetDeclaringClass(), new_value);
     return 0;  // success
@@ -395,19 +381,18 @@
 }
 
 extern "C" int artSet64StaticFromCode(uint32_t field_idx, mirror::ArtMethod* referrer,
-                                      uint64_t new_value, Thread* self,
-                                      StackReference<mirror::ArtMethod>* sp)
+                                      uint64_t new_value, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite,
                                           sizeof(int64_t));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     // Compiled code can't use transactional mode.
     field->Set64<false>(field->GetDeclaringClass(), new_value);
     return 0;  // success
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, self, sizeof(int64_t));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     // Compiled code can't use transactional mode.
     field->Set64<false>(field->GetDeclaringClass(), new_value);
     return 0;  // success
@@ -416,22 +401,21 @@
 }
 
 extern "C" int artSetObjStaticFromCode(uint32_t field_idx, mirror::Object* new_value,
-                                       mirror::ArtMethod* referrer, Thread* self,
-                                       StackReference<mirror::ArtMethod>* sp)
+                                       mirror::ArtMethod* referrer, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticObjectWrite,
                                           sizeof(mirror::HeapReference<mirror::Object>));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     if (LIKELY(!field->IsPrimitiveType())) {
       // Compiled code can't use transactional mode.
       field->SetObj<false>(field->GetDeclaringClass(), new_value);
       return 0;  // success
     }
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode<StaticObjectWrite, true>(field_idx, referrer, self,
                                                      sizeof(mirror::HeapReference<mirror::Object>));
-  if (LIKELY(field != NULL)) {
+  if (LIKELY(field != nullptr)) {
     // Compiled code can't use transactional mode.
     field->SetObj<false>(field->GetDeclaringClass(), new_value);
     return 0;  // success
@@ -440,12 +424,12 @@
 }
 
 extern "C" int artSet8InstanceFromCode(uint32_t field_idx, mirror::Object* obj, uint8_t new_value,
-                                       mirror::ArtMethod* referrer, Thread* self,
-                                       StackReference<mirror::ArtMethod>* sp)
+                                       mirror::ArtMethod* referrer, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
                                           sizeof(int8_t));
-  if (LIKELY(field != NULL && obj != NULL)) {
+  if (LIKELY(field != nullptr && obj != nullptr)) {
     Primitive::Type type = field->GetTypeAsPrimitiveType();
     // Compiled code can't use transactional mode.
     if (type == Primitive::kPrimBoolean) {
@@ -456,15 +440,14 @@
     }
     return 0;  // success
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   {
     StackHandleScope<1> hs(self);
     HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(&obj));
     field = FindFieldFromCode<InstancePrimitiveWrite, true>(field_idx, referrer, self,
                                                             sizeof(int8_t));
   }
-  if (LIKELY(field != NULL)) {
-    if (UNLIKELY(obj == NULL)) {
+  if (LIKELY(field != nullptr)) {
+    if (UNLIKELY(obj == nullptr)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
       ThrowNullPointerExceptionForFieldAccess(throw_location, field, false);
     } else {
@@ -482,12 +465,12 @@
 }
 
 extern "C" int artSet16InstanceFromCode(uint32_t field_idx, mirror::Object* obj, uint16_t new_value,
-                                        mirror::ArtMethod* referrer, Thread* self,
-                                        StackReference<mirror::ArtMethod>* sp)
+                                        mirror::ArtMethod* referrer, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
                                           sizeof(int16_t));
-  if (LIKELY(field != NULL && obj != NULL)) {
+  if (LIKELY(field != nullptr && obj != nullptr)) {
     Primitive::Type type = field->GetTypeAsPrimitiveType();
     // Compiled code can't use transactional mode.
     if (type == Primitive::kPrimChar) {
@@ -498,15 +481,14 @@
     }
     return 0;  // success
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   {
     StackHandleScope<1> hs(self);
     HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(&obj));
     field = FindFieldFromCode<InstancePrimitiveWrite, true>(field_idx, referrer, self,
                                                             sizeof(int16_t));
   }
-  if (LIKELY(field != NULL)) {
-    if (UNLIKELY(obj == NULL)) {
+  if (LIKELY(field != nullptr)) {
+    if (UNLIKELY(obj == nullptr)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
       ThrowNullPointerExceptionForFieldAccess(throw_location, field, false);
     } else {
@@ -525,25 +507,24 @@
 }
 
 extern "C" int artSet32InstanceFromCode(uint32_t field_idx, mirror::Object* obj, uint32_t new_value,
-                                        mirror::ArtMethod* referrer, Thread* self,
-                                        StackReference<mirror::ArtMethod>* sp)
+                                        mirror::ArtMethod* referrer, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
                                           sizeof(int32_t));
-  if (LIKELY(field != NULL && obj != NULL)) {
+  if (LIKELY(field != nullptr && obj != nullptr)) {
     // Compiled code can't use transactional mode.
     field->Set32<false>(obj, new_value);
     return 0;  // success
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   {
     StackHandleScope<1> hs(self);
     HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(&obj));
     field = FindFieldFromCode<InstancePrimitiveWrite, true>(field_idx, referrer, self,
                                                             sizeof(int32_t));
   }
-  if (LIKELY(field != NULL)) {
-    if (UNLIKELY(obj == NULL)) {
+  if (LIKELY(field != nullptr)) {
+    if (UNLIKELY(obj == nullptr)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
       ThrowNullPointerExceptionForFieldAccess(throw_location, field, false);
     } else {
@@ -556,25 +537,20 @@
 }
 
 extern "C" int artSet64InstanceFromCode(uint32_t field_idx, mirror::Object* obj, uint64_t new_value,
-                                        Thread* self, StackReference<mirror::ArtMethod>* sp)
+                                        mirror::ArtMethod* referrer, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  constexpr size_t frame_size = GetCalleeSaveFrameSize(kRuntimeISA, Runtime::kRefsOnly);
-  mirror::ArtMethod* referrer =
-      reinterpret_cast<StackReference<mirror::ArtMethod>*>(
-          reinterpret_cast<uint8_t*>(sp) + frame_size)->AsMirrorPtr();
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
                                           sizeof(int64_t));
-  if (LIKELY(field != NULL  && obj != NULL)) {
+  if (LIKELY(field != nullptr  && obj != nullptr)) {
     // Compiled code can't use transactional mode.
     field->Set64<false>(obj, new_value);
     return 0;  // success
   }
-  sp->Assign(Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsOnly));
-  self->SetTopOfStack(sp, 0);
   field = FindFieldFromCode<InstancePrimitiveWrite, true>(field_idx, referrer, self,
                                                           sizeof(int64_t));
-  if (LIKELY(field != NULL)) {
-    if (UNLIKELY(obj == NULL)) {
+  if (LIKELY(field != nullptr)) {
+    if (UNLIKELY(obj == nullptr)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
       ThrowNullPointerExceptionForFieldAccess(throw_location, field, false);
     } else {
@@ -588,21 +564,20 @@
 
 extern "C" int artSetObjInstanceFromCode(uint32_t field_idx, mirror::Object* obj,
                                          mirror::Object* new_value,
-                                         mirror::ArtMethod* referrer, Thread* self,
-                                         StackReference<mirror::ArtMethod>* sp)
+                                         mirror::ArtMethod* referrer, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite,
                                           sizeof(mirror::HeapReference<mirror::Object>));
-  if (LIKELY(field != NULL && obj != NULL)) {
+  if (LIKELY(field != nullptr && obj != nullptr)) {
     // Compiled code can't use transactional mode.
     field->SetObj<false>(obj, new_value);
     return 0;  // success
   }
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode<InstanceObjectWrite, true>(field_idx, referrer, self,
                                                        sizeof(mirror::HeapReference<mirror::Object>));
-  if (LIKELY(field != NULL)) {
-    if (UNLIKELY(obj == NULL)) {
+  if (LIKELY(field != nullptr)) {
+    if (UNLIKELY(obj == nullptr)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
       ThrowNullPointerExceptionForFieldAccess(throw_location, field, false);
     } else {
diff --git a/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc b/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc
index 06bbabc..e336543 100644
--- a/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc
@@ -25,10 +25,9 @@
  * Handle fill array data by copying appropriate part of dex file into array.
  */
 extern "C" int artHandleFillArrayDataFromCode(uint32_t payload_offset, mirror::Array* array,
-                                              mirror::ArtMethod* method, Thread* self,
-                                              StackReference<mirror::ArtMethod>* sp)
+                                              mirror::ArtMethod* method, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+  ScopedQuickEntrypointChecks sqec(self);
   const uint16_t* const insns = method->GetCodeItem()->insns_;
   const Instruction::ArrayDataPayload* payload =
       reinterpret_cast<const Instruction::ArrayDataPayload*>(insns + payload_offset);
diff --git a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
index 42ace40..f78273f 100644
--- a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
@@ -15,6 +15,7 @@
  */
 
 #include "callee_save_frame.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
 #include "instruction_set.h"
 #include "instrumentation.h"
 #include "mirror/art_method-inl.h"
@@ -27,10 +28,9 @@
 extern "C" const void* artInstrumentationMethodEntryFromCode(mirror::ArtMethod* method,
                                                              mirror::Object* this_object,
                                                              Thread* self,
-                                                             StackReference<mirror::ArtMethod>* sp,
                                                              uintptr_t lr)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
+  ScopedQuickEntrypointChecks sqec(self);
   instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
   const void* result;
   if (instrumentation->IsDeoptimized(method)) {
@@ -38,8 +38,7 @@
   } else {
     result = instrumentation->GetQuickCodeFor(method);
   }
-  DCHECK((result != Runtime::Current()->GetClassLinker()->GetQuickToInterpreterBridgeTrampoline())
-         || !Runtime::Current()->GetHeap()->HasImageSpace());
+  DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge(result));
   bool interpreter_entry = (result == GetQuickToInterpreterBridge());
   instrumentation->PushInstrumentationStackFrame(self, method->IsStatic() ? nullptr : this_object,
                                                  method, lr, interpreter_entry);
@@ -52,23 +51,19 @@
                                                               uint64_t gpr_result,
                                                               uint64_t fpr_result)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  // TODO: use FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly) not the hand inlined below.
-  //       We use the hand inline version to ensure the return_pc is assigned before verifying the
-  //       stack.
-  // Be aware the store below may well stomp on an incoming argument.
-  Locks::mutator_lock_->AssertSharedHeld(self);
-  Runtime* runtime = Runtime::Current();
-  sp->Assign(runtime->GetCalleeSaveMethod(Runtime::kRefsOnly));
-  uint32_t return_pc_offset = GetCalleeSavePCOffset(kRuntimeISA, Runtime::kRefsOnly);
+  // Compute address of return PC and sanity check that it currently holds 0.
+  size_t return_pc_offset = GetCalleeSaveReturnPcOffset(kRuntimeISA, Runtime::kRefsOnly);
   uintptr_t* return_pc = reinterpret_cast<uintptr_t*>(reinterpret_cast<uint8_t*>(sp) +
                                                       return_pc_offset);
   CHECK_EQ(*return_pc, 0U);
-  self->SetTopOfStack(sp, 0);
-  self->VerifyStack();
+
+  // Pop the frame filling in the return pc. The low half of the return value is 0 when
+  // deoptimization shouldn't be performed with the high-half having the return address. When
+  // deoptimization should be performed the low half is zero and the high-half the address of the
+  // deoptimization entry point.
   instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
   TwoWordReturn return_or_deoptimize_pc = instrumentation->PopInstrumentationStackFrame(
       self, return_pc, gpr_result, fpr_result);
-  self->VerifyStack();
   return return_or_deoptimize_pc;
 }
 
diff --git a/runtime/entrypoints/quick/quick_jni_entrypoints.cc b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
index c239535..c1276b5 100644
--- a/runtime/entrypoints/quick/quick_jni_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
@@ -15,6 +15,7 @@
  */
 
 #include "entrypoints/entrypoint_utils-inl.h"
+#include "mirror/art_method-inl.h"
 #include "mirror/object-inl.h"
 #include "thread-inl.h"
 #include "verify_object-inl.h"
diff --git a/runtime/entrypoints/quick/quick_lock_entrypoints.cc b/runtime/entrypoints/quick/quick_lock_entrypoints.cc
index 92c0841..8ceac97 100644
--- a/runtime/entrypoints/quick/quick_lock_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_lock_entrypoints.cc
@@ -20,12 +20,11 @@
 
 namespace art {
 
-extern "C" int artLockObjectFromCode(mirror::Object* obj, Thread* self,
-                                     StackReference<mirror::ArtMethod>* sp)
+extern "C" int artLockObjectFromCode(mirror::Object* obj, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
     NO_THREAD_SAFETY_ANALYSIS /* EXCLUSIVE_LOCK_FUNCTION(Monitor::monitor_lock_) */ {
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  if (UNLIKELY(obj == NULL)) {
+  ScopedQuickEntrypointChecks sqec(self);
+  if (UNLIKELY(obj == nullptr)) {
     ThrowLocation throw_location(self->GetCurrentLocationForThrow());
     ThrowNullPointerException(&throw_location,
                               "Null reference used for synchronization (monitor-enter)");
@@ -43,12 +42,11 @@
   }
 }
 
-extern "C" int artUnlockObjectFromCode(mirror::Object* obj, Thread* self,
-                                       StackReference<mirror::ArtMethod>* sp)
+extern "C" int artUnlockObjectFromCode(mirror::Object* obj, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
     NO_THREAD_SAFETY_ANALYSIS /* UNLOCK_FUNCTION(Monitor::monitor_lock_) */ {
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  if (UNLIKELY(obj == NULL)) {
+  ScopedQuickEntrypointChecks sqec(self);
+  if (UNLIKELY(obj == nullptr)) {
     ThrowLocation throw_location(self->GetCurrentLocationForThrow());
     ThrowNullPointerException(&throw_location,
                               "Null reference used for synchronization (monitor-exit)");
diff --git a/runtime/entrypoints/quick/quick_thread_entrypoints.cc b/runtime/entrypoints/quick/quick_thread_entrypoints.cc
index ea75fb6..87e0c6e 100644
--- a/runtime/entrypoints/quick/quick_thread_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_thread_entrypoints.cc
@@ -19,10 +19,9 @@
 
 namespace art {
 
-extern "C" void artTestSuspendFromCode(Thread* self, StackReference<mirror::ArtMethod>* sp)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+extern "C" void artTestSuspendFromCode(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // Called when suspend count check value is 0 and thread->suspend_count_ != 0
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+  ScopedQuickEntrypointChecks sqec(self);
   self->CheckSuspend();
 }
 
diff --git a/runtime/entrypoints/quick/quick_throw_entrypoints.cc b/runtime/entrypoints/quick/quick_throw_entrypoints.cc
index 13decc8..25df40b 100644
--- a/runtime/entrypoints/quick/quick_throw_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_throw_entrypoints.cc
@@ -24,16 +24,14 @@
 namespace art {
 
 // Deliver an exception that's pending on thread helping set up a callee save frame on the way.
-extern "C" void artDeliverPendingExceptionFromCode(Thread* thread,
-                                                   StackReference<mirror::ArtMethod>* sp)
+extern "C" void artDeliverPendingExceptionFromCode(Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
-  thread->QuickDeliverException();
+  ScopedQuickEntrypointChecks sqec(self);
+  self->QuickDeliverException();
 }
 
 // Called by generated call to throw an exception.
-extern "C" void artDeliverExceptionFromCode(mirror::Throwable* exception, Thread* self,
-                                            StackReference<mirror::ArtMethod>* sp)
+extern "C" void artDeliverExceptionFromCode(mirror::Throwable* exception, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   /*
    * exception may be NULL, in which case this routine should
@@ -42,9 +40,9 @@
    * and threw a NPE if NULL.  This routine responsible for setting
    * exception_ in thread and delivering the exception.
    */
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
+  ScopedQuickEntrypointChecks sqec(self);
   ThrowLocation throw_location = self->GetCurrentLocationForThrow();
-  if (exception == NULL) {
+  if (exception == nullptr) {
     self->ThrowNewException(throw_location, "Ljava/lang/NullPointerException;",
                             "throw with null exception");
   } else {
@@ -54,10 +52,9 @@
 }
 
 // Called by generated call to throw a NPE exception.
-extern "C" void artThrowNullPointerExceptionFromCode(Thread* self,
-                                                     StackReference<mirror::ArtMethod>* sp)
+extern "C" void artThrowNullPointerExceptionFromCode(Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
+  ScopedQuickEntrypointChecks sqec(self);
   self->NoteSignalBeingHandled();
   ThrowLocation throw_location = self->GetCurrentLocationForThrow();
   ThrowNullPointerExceptionFromDexPC(throw_location);
@@ -66,52 +63,50 @@
 }
 
 // Called by generated call to throw an arithmetic divide by zero exception.
-extern "C" void artThrowDivZeroFromCode(Thread* self, StackReference<mirror::ArtMethod>* sp)
+extern "C" void artThrowDivZeroFromCode(Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
+  ScopedQuickEntrypointChecks sqec(self);
   ThrowArithmeticExceptionDivideByZero();
   self->QuickDeliverException();
 }
 
 // Called by generated call to throw an array index out of bounds exception.
-extern "C" void artThrowArrayBoundsFromCode(int index, int length, Thread* self,
-                                            StackReference<mirror::ArtMethod>*sp)
+extern "C" void artThrowArrayBoundsFromCode(int index, int length, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
+  ScopedQuickEntrypointChecks sqec(self);
   ThrowArrayIndexOutOfBoundsException(index, length);
   self->QuickDeliverException();
 }
 
-extern "C" void artThrowStackOverflowFromCode(Thread* self, StackReference<mirror::ArtMethod>* sp)
+extern "C" void artThrowStackOverflowFromCode(Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
+  ScopedQuickEntrypointChecks sqec(self);
   self->NoteSignalBeingHandled();
   ThrowStackOverflowError(self);
   self->NoteSignalHandlerDone();
   self->QuickDeliverException();
 }
 
-extern "C" void artThrowNoSuchMethodFromCode(int32_t method_idx, Thread* self,
-                                             StackReference<mirror::ArtMethod>* sp)
+extern "C" void artThrowNoSuchMethodFromCode(int32_t method_idx, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
+  ScopedQuickEntrypointChecks sqec(self);
   ThrowNoSuchMethodError(method_idx);
   self->QuickDeliverException();
 }
 
 extern "C" void artThrowClassCastException(mirror::Class* dest_type, mirror::Class* src_type,
-                                           Thread* self, StackReference<mirror::ArtMethod>* sp)
+                                           Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
-  CHECK(!dest_type->IsAssignableFrom(src_type));
+  ScopedQuickEntrypointChecks sqec(self);
+  DCHECK(!dest_type->IsAssignableFrom(src_type));
   ThrowClassCastException(dest_type, src_type);
   self->QuickDeliverException();
 }
 
 extern "C" void artThrowArrayStoreException(mirror::Object* array, mirror::Object* value,
-                                            Thread* self, StackReference<mirror::ArtMethod>* sp)
+                                            Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
+  ScopedQuickEntrypointChecks sqec(self);
   ThrowArrayStoreException(value->GetClass(), array->GetClass());
   self->QuickDeliverException();
 }
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 96903db..af341bb 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -19,6 +19,7 @@
 #include "dex_file-inl.h"
 #include "dex_instruction-inl.h"
 #include "entrypoints/entrypoint_utils-inl.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
 #include "gc/accounting/card_table-inl.h"
 #include "instruction_set.h"
 #include "interpreter/interpreter.h"
@@ -465,7 +466,7 @@
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // Ensure we don't get thread suspension until the object arguments are safely in the shadow
   // frame.
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
+  ScopedQuickEntrypointChecks sqec(self);
 
   if (method->IsAbstract()) {
     ThrowAbstractMethodError(method);
@@ -504,7 +505,7 @@
         return 0;
       }
     }
-    JValue result = interpreter::EnterInterpreterFromStub(self, mh, code_item, *shadow_frame);
+    JValue result = interpreter::EnterInterpreterFromEntryPoint(self, &mh, code_item, shadow_frame);
     // Pop transition.
     self->PopManagedStackFragment(fragment);
     // No need to restore the args since the method has already been run by the interpreter.
@@ -592,7 +593,6 @@
       self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments");
   // Register the top of the managed stack, making stack crawlable.
   DCHECK_EQ(sp->AsMirrorPtr(), proxy_method) << PrettyMethod(proxy_method);
-  self->SetTopOfStack(sp, 0);
   DCHECK_EQ(proxy_method->GetFrameSizeInBytes(),
             Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes())
       << PrettyMethod(proxy_method);
@@ -677,7 +677,7 @@
                                                     Thread* self,
                                                     StackReference<mirror::ArtMethod>* sp)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
+  ScopedQuickEntrypointChecks sqec(self);
   // Start new JNI local reference state
   JNIEnvExt* env = self->GetJniEnv();
   ScopedObjectAccessUnchecked soa(env);
@@ -949,7 +949,7 @@
 
   virtual ~BuildNativeCallFrameStateMachine() {}
 
-  bool HavePointerGpr() {
+  bool HavePointerGpr() const {
     return gpr_index_ > 0;
   }
 
@@ -964,7 +964,7 @@
     }
   }
 
-  bool HaveHandleScopeGpr() {
+  bool HaveHandleScopeGpr() const {
     return gpr_index_ > 0;
   }
 
@@ -980,7 +980,7 @@
     }
   }
 
-  bool HaveIntGpr() {
+  bool HaveIntGpr() const {
     return gpr_index_ > 0;
   }
 
@@ -995,17 +995,17 @@
     }
   }
 
-  bool HaveLongGpr() {
+  bool HaveLongGpr() const {
     return gpr_index_ >= kRegistersNeededForLong + (LongGprNeedsPadding() ? 1 : 0);
   }
 
-  bool LongGprNeedsPadding() {
+  bool LongGprNeedsPadding() const {
     return kRegistersNeededForLong > 1 &&     // only pad when using multiple registers
         kAlignLongOnStack &&                  // and when it needs alignment
         (gpr_index_ & 1) == 1;                // counter is odd, see constructor
   }
 
-  bool LongStackNeedsPadding() {
+  bool LongStackNeedsPadding() const {
     return kRegistersNeededForLong > 1 &&     // only pad when using multiple registers
         kAlignLongOnStack &&                  // and when it needs 8B alignment
         (stack_entries_ & 1) == 1;            // counter is odd
@@ -1041,7 +1041,7 @@
     }
   }
 
-  bool HaveFloatFpr() {
+  bool HaveFloatFpr() const {
     return fpr_index_ > 0;
   }
 
@@ -1076,17 +1076,17 @@
     }
   }
 
-  bool HaveDoubleFpr() {
+  bool HaveDoubleFpr() const {
     return fpr_index_ >= kRegistersNeededForDouble + (DoubleFprNeedsPadding() ? 1 : 0);
   }
 
-  bool DoubleFprNeedsPadding() {
+  bool DoubleFprNeedsPadding() const {
     return kRegistersNeededForDouble > 1 &&     // only pad when using multiple registers
         kAlignDoubleOnStack &&                  // and when it needs alignment
         (fpr_index_ & 1) == 1;                  // counter is odd, see constructor
   }
 
-  bool DoubleStackNeedsPadding() {
+  bool DoubleStackNeedsPadding() const {
     return kRegistersNeededForDouble > 1 &&     // only pad when using multiple registers
         kAlignDoubleOnStack &&                  // and when it needs 8B alignment
         (stack_entries_ & 1) == 1;              // counter is odd
@@ -1121,15 +1121,15 @@
     }
   }
 
-  uint32_t getStackEntries() {
+  uint32_t GetStackEntries() const {
     return stack_entries_;
   }
 
-  uint32_t getNumberOfUsedGprs() {
+  uint32_t GetNumberOfUsedGprs() const {
     return kNumNativeGprArgs - gpr_index_;
   }
 
-  uint32_t getNumberOfUsedFprs() {
+  uint32_t GetNumberOfUsedFprs() const {
     return kNumNativeFprArgs - fpr_index_;
   }
 
@@ -1154,7 +1154,7 @@
   uint32_t fpr_index_;      // Number of free FPRs
   uint32_t stack_entries_;  // Stack entries are in multiples of 32b, as floats are usually not
                             // extended
-  T* delegate_;             // What Push implementation gets called
+  T* const delegate_;             // What Push implementation gets called
 };
 
 // Computes the sizes of register stacks and call stack area. Handling of references can be extended
@@ -1168,18 +1168,19 @@
 
   virtual ~ComputeNativeCallFrameSize() {}
 
-  uint32_t GetStackSize() {
+  uint32_t GetStackSize() const {
     return num_stack_entries_ * sizeof(uintptr_t);
   }
 
-  uint8_t* LayoutCallStack(uint8_t* sp8) {
+  uint8_t* LayoutCallStack(uint8_t* sp8) const {
     sp8 -= GetStackSize();
     // Align by kStackAlignment.
     sp8 = reinterpret_cast<uint8_t*>(RoundDown(reinterpret_cast<uintptr_t>(sp8), kStackAlignment));
     return sp8;
   }
 
-  uint8_t* LayoutCallRegisterStacks(uint8_t* sp8, uintptr_t** start_gpr, uint32_t** start_fpr) {
+  uint8_t* LayoutCallRegisterStacks(uint8_t* sp8, uintptr_t** start_gpr, uint32_t** start_fpr)
+      const {
     // Assumption is OK right now, as we have soft-float arm
     size_t fregs = BuildNativeCallFrameStateMachine<ComputeNativeCallFrameSize>::kNumNativeFprArgs;
     sp8 -= fregs * sizeof(uintptr_t);
@@ -1191,7 +1192,7 @@
   }
 
   uint8_t* LayoutNativeCall(uint8_t* sp8, uintptr_t** start_stack, uintptr_t** start_gpr,
-                            uint32_t** start_fpr) {
+                            uint32_t** start_fpr) const {
     // Native call stack.
     sp8 = LayoutCallStack(sp8);
     *start_stack = reinterpret_cast<uintptr_t*>(sp8);
@@ -1215,6 +1216,7 @@
       Primitive::Type cur_type_ = Primitive::GetType(shorty[i]);
       switch (cur_type_) {
         case Primitive::kPrimNot:
+          // TODO: fix abuse of mirror types.
           sm.AdvanceHandleScope(
               reinterpret_cast<mirror::Object*>(0x12345678));
           break;
@@ -1240,7 +1242,7 @@
       }
     }
 
-    num_stack_entries_ = sm.getStackEntries();
+    num_stack_entries_ = sm.GetStackEntries();
   }
 
   void PushGpr(uintptr_t /* val */) {
@@ -1310,7 +1312,7 @@
   }
 
   // Adds space for the cookie. Note: may leave stack unaligned.
-  void LayoutCookie(uint8_t** sp) {
+  void LayoutCookie(uint8_t** sp) const {
     // Reference cookie and padding
     *sp -= 8;
   }
@@ -1457,11 +1459,11 @@
     return handle_scope_->GetHandle(0).GetReference();
   }
 
-  jobject GetFirstHandleScopeJObject() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  jobject GetFirstHandleScopeJObject() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return handle_scope_->GetHandle(0).ToJObject();
   }
 
-  void* GetBottomOfUsedArea() {
+  void* GetBottomOfUsedArea() const {
     return bottom_of_used_area_;
   }
 
@@ -1608,13 +1610,13 @@
   uint32_t shorty_len = 0;
   const char* shorty = called->GetShorty(&shorty_len);
 
-  // Run the visitor.
+  // Run the visitor and update sp.
   BuildGenericJniFrameVisitor visitor(self, called->IsStatic(), shorty, shorty_len, &sp);
   visitor.VisitArguments();
   visitor.FinalizeHandleScope(self);
 
   // Fix up managed-stack things in Thread.
-  self->SetTopOfStack(sp, 0);
+  self->SetTopOfStack(sp);
 
   self->VerifyStack();
 
@@ -1743,10 +1745,11 @@
 static TwoWordReturn artInvokeCommon(uint32_t method_idx, mirror::Object* this_object,
                                      mirror::ArtMethod* caller_method,
                                      Thread* self, StackReference<mirror::ArtMethod>* sp) {
+  ScopedQuickEntrypointChecks sqec(self);
+  DCHECK_EQ(sp->AsMirrorPtr(), Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs));
   mirror::ArtMethod* method = FindMethodFast(method_idx, this_object, caller_method, access_check,
                                              type);
   if (UNLIKELY(method == nullptr)) {
-    FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
     const DexFile* dex_file = caller_method->GetDeclaringClass()->GetDexCache()->GetDexFile();
     uint32_t shorty_len;
     const char* shorty = dex_file->GetMethodShorty(dex_file->GetMethodId(method_idx), &shorty_len);
@@ -1851,21 +1854,20 @@
                                                       Thread* self,
                                                       StackReference<mirror::ArtMethod>* sp)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
   mirror::ArtMethod* method;
   if (LIKELY(interface_method->GetDexMethodIndex() != DexFile::kDexNoIndex)) {
     method = this_object->GetClass()->FindVirtualMethodForInterface(interface_method);
     if (UNLIKELY(method == NULL)) {
-      FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
       ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(interface_method, this_object,
                                                                  caller_method);
       return GetTwoWordFailureValue();  // Failure.
     }
   } else {
-    FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
     DCHECK(interface_method == Runtime::Current()->GetResolutionMethod());
 
     // Find the caller PC.
-    constexpr size_t pc_offset = GetCalleeSavePCOffset(kRuntimeISA, Runtime::kRefsAndArgs);
+    constexpr size_t pc_offset = GetCalleeSaveReturnPcOffset(kRuntimeISA, Runtime::kRefsAndArgs);
     uintptr_t caller_pc = *reinterpret_cast<uintptr_t*>(reinterpret_cast<uint8_t*>(sp) + pc_offset);
 
     // Map the caller PC to a dex PC.
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc
index 02b8a5b..a9af754 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc
@@ -55,9 +55,10 @@
       NO_THREAD_SAFETY_ANALYSIS {
     mirror::ArtMethod* save_method = CreateCalleeSaveMethod(isa, type);
     QuickMethodFrameInfo frame_info = save_method->GetQuickFrameInfo();
-    EXPECT_EQ(save_method->GetReturnPcOffsetInBytes(), pc_offset) << "Expected and real pc offset"
-        " differs for " << type << " core spills=" << std::hex << frame_info.CoreSpillMask() <<
-        " fp spills=" << frame_info.FpSpillMask() << std::dec << " ISA " << isa;
+    EXPECT_EQ(save_method->GetReturnPcOffset().SizeValue(), pc_offset)
+        << "Expected and real pc offset differs for " << type
+        << " core spills=" << std::hex << frame_info.CoreSpillMask()
+        << " fp spills=" << frame_info.FpSpillMask() << std::dec << " ISA " << isa;
   }
 };
 
@@ -97,11 +98,11 @@
   // Note: we can only check against the kRuntimeISA, because the ArtMethod computation uses
   // sizeof(void*), which is wrong when the target bitwidth is not the same as the host's.
   CheckPCOffset(kRuntimeISA, Runtime::kRefsAndArgs,
-                GetCalleeSavePCOffset(kRuntimeISA, Runtime::kRefsAndArgs));
+                GetCalleeSaveReturnPcOffset(kRuntimeISA, Runtime::kRefsAndArgs));
   CheckPCOffset(kRuntimeISA, Runtime::kRefsOnly,
-                GetCalleeSavePCOffset(kRuntimeISA, Runtime::kRefsOnly));
+                GetCalleeSaveReturnPcOffset(kRuntimeISA, Runtime::kRefsOnly));
   CheckPCOffset(kRuntimeISA, Runtime::kSaveAll,
-                GetCalleeSavePCOffset(kRuntimeISA, Runtime::kSaveAll));
+                GetCalleeSaveReturnPcOffset(kRuntimeISA, Runtime::kSaveAll));
 }
 
 }  // namespace art
diff --git a/runtime/entrypoints/runtime_asm_entrypoints.h b/runtime/entrypoints/runtime_asm_entrypoints.h
new file mode 100644
index 0000000..db36a73
--- /dev/null
+++ b/runtime/entrypoints/runtime_asm_entrypoints.h
@@ -0,0 +1,117 @@
+/*
+ * 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_RUNTIME_ENTRYPOINTS_RUNTIME_ASM_ENTRYPOINTS_H_
+#define ART_RUNTIME_ENTRYPOINTS_RUNTIME_ASM_ENTRYPOINTS_H_
+
+namespace art {
+
+#ifndef BUILDING_LIBART
+#error "File and symbols only for use within libart."
+#endif
+
+extern "C" void* art_jni_dlsym_lookup_stub(JNIEnv*, jobject);
+static inline const void* GetJniDlsymLookupStub() {
+  return reinterpret_cast<const void*>(art_jni_dlsym_lookup_stub);
+}
+
+// Return the address of portable stub code for handling IMT conflicts.
+extern "C" void art_portable_imt_conflict_trampoline(mirror::ArtMethod*);
+static inline const void* GetPortableImtConflictStub() {
+  return reinterpret_cast<const void*>(art_portable_imt_conflict_trampoline);
+}
+
+// Return the address of quick stub code for handling IMT conflicts.
+extern "C" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*);
+static inline const void* GetQuickImtConflictStub() {
+  return reinterpret_cast<const void*>(art_quick_imt_conflict_trampoline);
+}
+
+// Return the address of portable stub code for bridging from portable code to the interpreter.
+extern "C" void art_portable_to_interpreter_bridge(mirror::ArtMethod*);
+static inline const void* GetPortableToInterpreterBridge() {
+  return reinterpret_cast<const void*>(art_portable_to_interpreter_bridge);
+}
+
+// Return the address of quick stub code for bridging from quick code to the interpreter.
+extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*);
+static inline const void* GetQuickToInterpreterBridge() {
+  return reinterpret_cast<const void*>(art_quick_to_interpreter_bridge);
+}
+
+// Return the address of portable stub code for bridging from portable code to quick.
+static inline const void* GetPortableToQuickBridge() {
+  // TODO: portable to quick bridge. Bug: 8196384
+  return GetPortableToInterpreterBridge();
+}
+
+// Return the address of quick stub code for bridging from quick code to portable.
+static inline const void* GetQuickToPortableBridge() {
+  // TODO: quick to portable bridge. Bug: 8196384
+  return GetQuickToInterpreterBridge();
+}
+
+// Return the address of quick stub code for handling JNI calls.
+extern "C" void art_quick_generic_jni_trampoline(mirror::ArtMethod*);
+static inline const void* GetQuickGenericJniStub() {
+  return reinterpret_cast<const void*>(art_quick_generic_jni_trampoline);
+}
+
+// Return the address of portable stub code for handling transitions into the proxy invoke handler.
+extern "C" void art_portable_proxy_invoke_handler();
+static inline const void* GetPortableProxyInvokeHandler() {
+  return reinterpret_cast<const void*>(art_portable_proxy_invoke_handler);
+}
+
+// Return the address of quick stub code for handling transitions into the proxy invoke handler.
+extern "C" void art_quick_proxy_invoke_handler();
+static inline const void* GetQuickProxyInvokeHandler() {
+  return reinterpret_cast<const void*>(art_quick_proxy_invoke_handler);
+}
+
+// Return the address of portable stub code for resolving a method at first call.
+extern "C" void art_portable_resolution_trampoline(mirror::ArtMethod*);
+static inline const void* GetPortableResolutionStub() {
+  return reinterpret_cast<const void*>(art_portable_resolution_trampoline);
+}
+
+// Return the address of quick stub code for resolving a method at first call.
+extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*);
+static inline const void* GetQuickResolutionStub() {
+  return reinterpret_cast<const void*>(art_quick_resolution_trampoline);
+}
+
+// Entry point for quick code that performs deoptimization.
+extern "C" void art_quick_deoptimize();
+static inline const void* GetQuickDeoptimizationEntryPoint() {
+  return reinterpret_cast<const void*>(art_quick_deoptimize);
+}
+
+// Return address of instrumentation entry point used by non-interpreter based tracing.
+extern "C" void art_quick_instrumentation_entry(void*);
+static inline const void* GetQuickInstrumentationEntryPoint() {
+  return reinterpret_cast<const void*>(art_quick_instrumentation_entry);
+}
+
+// The return_pc of instrumentation exit stub.
+extern "C" void art_quick_instrumentation_exit();
+static inline const void* GetQuickInstrumentationExitPc() {
+  return reinterpret_cast<const void*>(art_quick_instrumentation_exit);
+}
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_ENTRYPOINTS_RUNTIME_ASM_ENTRYPOINTS_H_
diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc
index 3a17eca..1365cd4 100644
--- a/runtime/exception_test.cc
+++ b/runtime/exception_test.cc
@@ -43,7 +43,7 @@
     Handle<mirror::ClassLoader> class_loader(
         hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("ExceptionHandle"))));
     my_klass_ = class_linker_->FindClass(soa.Self(), "LExceptionHandle;", class_loader);
-    ASSERT_TRUE(my_klass_ != NULL);
+    ASSERT_TRUE(my_klass_ != nullptr);
     Handle<mirror::Class> klass(hs.NewHandle(my_klass_));
     class_linker_->EnsureInitialized(soa.Self(), klass, true, true);
     my_klass_ = klass.Get();
@@ -93,12 +93,12 @@
     const uint8_t* code_ptr = &fake_header_code_and_maps_[mapping_table_offset];
 
     method_f_ = my_klass_->FindVirtualMethod("f", "()I");
-    ASSERT_TRUE(method_f_ != NULL);
+    ASSERT_TRUE(method_f_ != nullptr);
     method_f_->SetEntryPointFromQuickCompiledCode(code_ptr);
     method_f_->SetNativeGcMap(&fake_gc_map_[0]);
 
     method_g_ = my_klass_->FindVirtualMethod("g", "(I)V");
-    ASSERT_TRUE(method_g_ != NULL);
+    ASSERT_TRUE(method_g_ != nullptr);
     method_g_->SetEntryPointFromQuickCompiledCode(code_ptr);
     method_g_->SetNativeGcMap(&fake_gc_map_[0]);
   }
@@ -122,7 +122,7 @@
   ScopedObjectAccess soa(Thread::Current());
   const DexFile::CodeItem* code_item = dex_->GetCodeItem(method_f_->GetCodeItemOffset());
 
-  ASSERT_TRUE(code_item != NULL);
+  ASSERT_TRUE(code_item != nullptr);
 
   ASSERT_EQ(2u, code_item->tries_size_);
   ASSERT_NE(0u, code_item->insns_size_in_code_units_);
@@ -163,19 +163,35 @@
   ScopedObjectAccess soa(env);
 
   std::vector<uintptr_t> fake_stack;
+  Runtime* r = Runtime::Current();
+  r->SetInstructionSet(kRuntimeISA);
+  mirror::ArtMethod* save_method = r->CreateCalleeSaveMethod(Runtime::kSaveAll);
+  r->SetCalleeSaveMethod(save_method, Runtime::kSaveAll);
+  QuickMethodFrameInfo frame_info = save_method->GetQuickFrameInfo();
+
   ASSERT_EQ(kStackAlignment, 16U);
   // ASSERT_EQ(sizeof(uintptr_t), sizeof(uint32_t));
 
+
   if (!kUsePortableCompiler) {
-    // Create two fake stack frames with mapping data created in SetUp. We map offset 3 in the code
-    // to dex pc 3.
+    // Create three fake stack frames with mapping data created in SetUp. We map offset 3 in the
+    // code to dex pc 3.
     const uint32_t dex_pc = 3;
 
+    // Create the stack frame for the callee save method, expected by the runtime.
+    fake_stack.push_back(reinterpret_cast<uintptr_t>(save_method));
+    for (size_t i = 0; i < frame_info.FrameSizeInBytes() - 2 * sizeof(uintptr_t);
+         i += sizeof(uintptr_t)) {
+      fake_stack.push_back(0);
+    }
+
+    fake_stack.push_back(method_g_->ToNativeQuickPc(dex_pc));  // return pc
+
     // Create/push fake 16byte stack frame for method g
     fake_stack.push_back(reinterpret_cast<uintptr_t>(method_g_));
     fake_stack.push_back(0);
     fake_stack.push_back(0);
-    fake_stack.push_back(method_f_->ToNativePc(dex_pc));  // return pc
+    fake_stack.push_back(method_f_->ToNativeQuickPc(dex_pc));  // return pc
 
     // Create/push fake 16byte stack frame for method f
     fake_stack.push_back(reinterpret_cast<uintptr_t>(method_f_));
@@ -183,7 +199,7 @@
     fake_stack.push_back(0);
     fake_stack.push_back(0xEBAD6070);  // return pc
 
-    // Pull Method* of NULL to terminate the trace
+    // Push Method* of NULL to terminate the trace
     fake_stack.push_back(0);
 
     // Push null values which will become null incoming arguments.
@@ -192,9 +208,7 @@
     fake_stack.push_back(0);
 
     // Set up thread to appear as if we called out of method_g_ at pc dex 3
-    thread->SetTopOfStack(
-        reinterpret_cast<StackReference<mirror::ArtMethod>*>(&fake_stack[0]),
-        method_g_->ToNativePc(dex_pc));  // return pc
+    thread->SetTopOfStack(reinterpret_cast<StackReference<mirror::ArtMethod>*>(&fake_stack[0]));
   } else {
     // Create/push fake 20-byte shadow frame for method g
     fake_stack.push_back(0);
@@ -215,33 +229,35 @@
   }
 
   jobject internal = thread->CreateInternalStackTrace<false>(soa);
-  ASSERT_TRUE(internal != NULL);
+  ASSERT_TRUE(internal != nullptr);
   jobjectArray ste_array = Thread::InternalStackTraceToStackTraceElementArray(soa, internal);
-  ASSERT_TRUE(ste_array != NULL);
+  ASSERT_TRUE(ste_array != nullptr);
   mirror::ObjectArray<mirror::StackTraceElement>* trace_array =
       soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>*>(ste_array);
 
-  ASSERT_TRUE(trace_array != NULL);
-  ASSERT_TRUE(trace_array->Get(0) != NULL);
+  ASSERT_TRUE(trace_array != nullptr);
+  ASSERT_TRUE(trace_array->Get(0) != nullptr);
   EXPECT_STREQ("ExceptionHandle",
                trace_array->Get(0)->GetDeclaringClass()->ToModifiedUtf8().c_str());
-  EXPECT_STREQ("ExceptionHandle.java", trace_array->Get(0)->GetFileName()->ToModifiedUtf8().c_str());
+  EXPECT_STREQ("ExceptionHandle.java",
+               trace_array->Get(0)->GetFileName()->ToModifiedUtf8().c_str());
   EXPECT_STREQ("g", trace_array->Get(0)->GetMethodName()->ToModifiedUtf8().c_str());
   EXPECT_EQ(37, trace_array->Get(0)->GetLineNumber());
 
-  ASSERT_TRUE(trace_array->Get(1) != NULL);
+  ASSERT_TRUE(trace_array->Get(1) != nullptr);
   EXPECT_STREQ("ExceptionHandle",
                trace_array->Get(1)->GetDeclaringClass()->ToModifiedUtf8().c_str());
-  EXPECT_STREQ("ExceptionHandle.java", trace_array->Get(1)->GetFileName()->ToModifiedUtf8().c_str());
+  EXPECT_STREQ("ExceptionHandle.java",
+               trace_array->Get(1)->GetFileName()->ToModifiedUtf8().c_str());
   EXPECT_STREQ("f", trace_array->Get(1)->GetMethodName()->ToModifiedUtf8().c_str());
   EXPECT_EQ(22, trace_array->Get(1)->GetLineNumber());
 
-#if !defined(ART_USE_PORTABLE_COMPILER)
-  thread->SetTopOfStack(NULL, 0);  // Disarm the assertion that no code is running when we detach.
-#else
-  thread->PopShadowFrame();
-  thread->PopShadowFrame();
-#endif
+  if (!kUsePortableCompiler) {
+    thread->SetTopOfStack(nullptr);  // Disarm the assertion that no code is running when we detach.
+  } else {
+    thread->PopShadowFrame();
+    thread->PopShadowFrame();
+  }
 }
 
 }  // namespace art
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index fede2f8..4ae929b 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -95,16 +95,29 @@
 FaultManager::~FaultManager() {
 }
 
+static void SetUpArtAction(struct sigaction* action) {
+  action->sa_sigaction = art_fault_handler;
+  sigemptyset(&action->sa_mask);
+  action->sa_flags = SA_SIGINFO | SA_ONSTACK;
+#if !defined(__APPLE__) && !defined(__mips__)
+  action->sa_restorer = nullptr;
+#endif
+}
+
+void FaultManager::EnsureArtActionInFrontOfSignalChain() {
+  if (initialized_) {
+    struct sigaction action;
+    SetUpArtAction(&action);
+    EnsureFrontOfChain(SIGSEGV, &action);
+  } else {
+    LOG(WARNING) << "Can't call " << __FUNCTION__ << " due to unitialized fault manager";
+  }
+}
 
 void FaultManager::Init() {
   CHECK(!initialized_);
   struct sigaction action;
-  action.sa_sigaction = art_fault_handler;
-  sigemptyset(&action.sa_mask);
-  action.sa_flags = SA_SIGINFO | SA_ONSTACK;
-#if !defined(__APPLE__) && !defined(__mips__)
-  action.sa_restorer = nullptr;
-#endif
+  SetUpArtAction(&action);
 
   // Set our signal handler now.
   int e = sigaction(SIGSEGV, &action, &oldaction_);
@@ -138,7 +151,6 @@
   //
   // If malloc calls abort, it will be holding its lock.
   // If the handler tries to call malloc, it will deadlock.
-
   VLOG(signals) << "Handling fault";
   if (IsInGeneratedCode(info, context, true)) {
     VLOG(signals) << "in generated code, looking for handler";
@@ -388,7 +400,7 @@
     // Inside of generated code, sp[0] is the method, so sp is the frame.
     StackReference<mirror::ArtMethod>* frame =
         reinterpret_cast<StackReference<mirror::ArtMethod>*>(sp);
-    self->SetTopOfStack(frame, 0);  // Since we don't necessarily have a dex pc, pass in 0.
+    self->SetTopOfStack(frame);
 #ifdef TEST_NESTED_SIGNAL
     // To test the nested signal handler we raise a signal here.  This will cause the
     // nested signal handler to be called and perform a longjmp back to the setjmp
diff --git a/runtime/fault_handler.h b/runtime/fault_handler.h
index 8b66a6f..adac4c2 100644
--- a/runtime/fault_handler.h
+++ b/runtime/fault_handler.h
@@ -45,6 +45,7 @@
 
   // Unclaim signals and delete registered handlers.
   void Shutdown();
+  void EnsureArtActionInFrontOfSignalChain();
 
   void HandleFault(int sig, siginfo_t* info, void* context);
   void HandleNestedSignal(int sig, siginfo_t* info, void* context);
@@ -128,7 +129,6 @@
   DISALLOW_COPY_AND_ASSIGN(JavaStackTraceHandler);
 };
 
-
 // Statically allocated so the the signal handler can Get access to it.
 extern FaultManager fault_manager;
 
diff --git a/runtime/gc/allocator/dlmalloc.cc b/runtime/gc/allocator/dlmalloc.cc
index a6a3ee7..fbeba7f 100644
--- a/runtime/gc/allocator/dlmalloc.cc
+++ b/runtime/gc/allocator/dlmalloc.cc
@@ -39,11 +39,11 @@
 
 
 static void art_heap_corruption(const char* function) {
-  LOG(FATAL) << "Corrupt heap detected in: " << function;
+  LOG(::art::FATAL) << "Corrupt heap detected in: " << function;
 }
 
 static void art_heap_usage_error(const char* function, void* p) {
-  LOG(FATAL) << "Incorrect use of function '" << function << "' argument " << p << " not expected";
+  LOG(::art::FATAL) << "Incorrect use of function '" << function << "' argument " << p << " not expected";
 }
 
 #include "globals.h"
@@ -63,7 +63,7 @@
     int rc = madvise(start, length, MADV_DONTNEED);
     if (UNLIKELY(rc != 0)) {
       errno = rc;
-      PLOG(FATAL) << "madvise failed during heap trimming";
+      PLOG(::art::FATAL) << "madvise failed during heap trimming";
     }
     size_t* reclaimed = reinterpret_cast<size_t*>(arg);
     *reclaimed += length;
diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc
index 0cea89d..fa531a7 100644
--- a/runtime/gc/allocator/rosalloc.cc
+++ b/runtime/gc/allocator/rosalloc.cc
@@ -24,6 +24,7 @@
 
 #include <map>
 #include <list>
+#include <sstream>
 #include <vector>
 
 namespace art {
@@ -264,7 +265,7 @@
       }
       break;
     default:
-      LOG(FATAL) << "Unreachable - page map type: " << page_map_type;
+      LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_type);
       break;
     }
     if (kIsDebugBuild) {
@@ -499,7 +500,7 @@
       case kPageMapLargeObject:
         return FreePages(self, ptr, false);
       case kPageMapLargeObjectPart:
-        LOG(FATAL) << "Unreachable - page map type: " << page_map_[pm_idx];
+        LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_[pm_idx]);
         return 0;
       case kPageMapRunPart: {
         // Find the beginning of the run.
@@ -514,11 +515,11 @@
         break;
       case kPageMapReleased:
       case kPageMapEmpty:
-        LOG(FATAL) << "Unreachable - page map type: " << page_map_[pm_idx];
+        LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_[pm_idx]);
         return 0;
       }
       default:
-        LOG(FATAL) << "Unreachable - page map type: " << page_map_[pm_idx];
+        LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_[pm_idx]);
         return 0;
     }
   }
@@ -1143,7 +1144,7 @@
 
 size_t RosAlloc::BulkFree(Thread* self, void** ptrs, size_t num_ptrs) {
   size_t freed_bytes = 0;
-  if (false) {
+  if ((false)) {
     // Used only to test Free() as GC uses only BulkFree().
     for (size_t i = 0; i < num_ptrs; ++i) {
       freed_bytes += FreeInternal(self, ptrs[i]);
@@ -1189,7 +1190,7 @@
         freed_bytes += FreePages(self, ptr, false);
         continue;
       } else {
-        LOG(FATAL) << "Unreachable - page map type: " << page_map_entry;
+        LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_entry);
       }
     } else {
       // Read the page map entries with a lock.
@@ -1215,7 +1216,7 @@
         freed_bytes += FreePages(self, ptr, false);
         continue;
       } else {
-        LOG(FATAL) << "Unreachable - page map type: " << page_map_entry;
+        LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_entry);
       }
     }
     DCHECK(run != nullptr);
@@ -1477,7 +1478,7 @@
       return IndexToBracketSize(idx);
     }
     default: {
-      LOG(FATAL) << "Unreachable - page map type: " << page_map_[pm_idx];
+      LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_[pm_idx]);
       break;
     }
   }
@@ -1593,7 +1594,7 @@
         break;
       }
       case kPageMapLargeObjectPart:
-        LOG(FATAL) << "Unreachable - page map type: " << pm;
+        LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm);
         break;
       case kPageMapRun: {
         // The start of a run.
@@ -1613,10 +1614,10 @@
         break;
       }
       case kPageMapRunPart:
-        LOG(FATAL) << "Unreachable - page map type: " << pm;
+        LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm);
         break;
       default:
-        LOG(FATAL) << "Unreachable - page map type: " << pm;
+        LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm);
         break;
     }
   }
@@ -1929,7 +1930,7 @@
           break;
         }
         case kPageMapLargeObjectPart:
-          LOG(FATAL) << "Unreachable - page map type: " << pm << std::endl << DumpPageMap();
+          LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm) << std::endl << DumpPageMap();
           break;
         case kPageMapRun: {
           // The start of a run.
@@ -1957,7 +1958,7 @@
         case kPageMapRunPart:
           // Fall-through.
         default:
-          LOG(FATAL) << "Unreachable - page map type: " << pm << std::endl << DumpPageMap();
+          LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm) << std::endl << DumpPageMap();
           break;
       }
     }
@@ -2146,7 +2147,7 @@
         ++i;
         break;  // Skip.
       default:
-        LOG(FATAL) << "Unreachable - page map type: " << pm;
+        LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm);
         break;
     }
   }
diff --git a/runtime/gc/collector/garbage_collector.cc b/runtime/gc/collector/garbage_collector.cc
index 07b61e6..9e6a800 100644
--- a/runtime/gc/collector/garbage_collector.cc
+++ b/runtime/gc/collector/garbage_collector.cc
@@ -18,6 +18,10 @@
 
 #include "garbage_collector.h"
 
+#define ATRACE_TAG ATRACE_TAG_DALVIK
+#include "cutils/trace.h"
+
+#include "base/dumpable.h"
 #include "base/histogram-inl.h"
 #include "base/logging.h"
 #include "base/mutex-inl.h"
@@ -188,7 +192,7 @@
   if (iterations == 0) {
     return;
   }
-  os << ConstDumpable<CumulativeLogger>(logger);
+  os << Dumpable<CumulativeLogger>(logger);
   const uint64_t total_ns = logger.GetTotalNs();
   double seconds = NsToMs(logger.GetTotalNs()) / 1000.0;
   const uint64_t freed_bytes = GetTotalFreedBytes();
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index 942b556..83da063 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -21,6 +21,9 @@
 #include <climits>
 #include <vector>
 
+#define ATRACE_TAG ATRACE_TAG_DALVIK
+#include "cutils/trace.h"
+
 #include "base/bounded_fifo.h"
 #include "base/logging.h"
 #include "base/macros.h"
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index 9459a3b..e141b6f 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -16,9 +16,10 @@
 
 #include "semi_space-inl.h"
 
+#include <climits>
 #include <functional>
 #include <numeric>
-#include <climits>
+#include <sstream>
 #include <vector>
 
 #include "base/logging.h"
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index b9d69d5..bceac44 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -24,6 +24,7 @@
 #include <vector>
 
 #include "base/allocator.h"
+#include "base/dumpable.h"
 #include "base/histogram-inl.h"
 #include "base/stl_util.h"
 #include "common_throws.h"
@@ -436,7 +437,7 @@
 MemMap* Heap::MapAnonymousPreferredAddress(const char* name, uint8_t* request_begin, size_t capacity,
                                            int prot_flags, std::string* out_error_str) {
   while (true) {
-    MemMap* map = MemMap::MapAnonymous(kMemMapSpaceName[0], request_begin, capacity,
+    MemMap* map = MemMap::MapAnonymous(name, request_begin, capacity,
                                        PROT_READ | PROT_WRITE, true, out_error_str);
     if (map != nullptr || request_begin == nullptr) {
       return map;
@@ -2137,6 +2138,13 @@
   } else {
     LOG(FATAL) << "Invalid current allocator " << current_allocator_;
   }
+  if (IsGcConcurrent()) {
+    // Disable concurrent GC check so that we don't have spammy JNI requests.
+    // This gets recalculated in GrowForUtilization. It is important that it is disabled /
+    // calculated in the same thread so that there aren't any races that can cause it to become
+    // permanantly disabled. b/17942071
+    concurrent_start_bytes_ = std::numeric_limits<size_t>::max();
+  }
   CHECK(collector != nullptr)
       << "Could not find garbage collector with collector_type="
       << static_cast<size_t>(collector_type_) << " and gc_type=" << gc_type;
@@ -2178,7 +2186,7 @@
               << percent_free << "% free, " << PrettySize(current_heap_size) << "/"
               << PrettySize(total_memory) << ", " << "paused " << pause_string.str()
               << " total " << PrettyDuration((duration / 1000) * 1000);
-    VLOG(heap) << ConstDumpable<TimingLogger>(*current_gc_iteration_.GetTimings());
+    VLOG(heap) << Dumpable<TimingLogger>(*current_gc_iteration_.GetTimings());
   }
   FinishGC(self, gc_type);
   // Inform DDMS that a GC completed.
@@ -2955,9 +2963,6 @@
       self->IsHandlingStackOverflow()) {
     return;
   }
-  // We already have a request pending, no reason to start more until we update
-  // concurrent_start_bytes_.
-  concurrent_start_bytes_ = std::numeric_limits<size_t>::max();
   JNIEnv* env = self->GetJniEnv();
   DCHECK(WellKnownClasses::java_lang_Daemons != nullptr);
   DCHECK(WellKnownClasses::java_lang_Daemons_requestGC != nullptr);
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index c09dca8..ff1e38b 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -32,7 +32,6 @@
 #include "gc/collector_type.h"
 #include "gc/space/large_object_space.h"
 #include "globals.h"
-#include "gtest/gtest.h"
 #include "instruction_set.h"
 #include "jni.h"
 #include "object_callbacks.h"
@@ -602,9 +601,6 @@
   void RemoveRememberedSet(space::Space* space);
 
   bool IsCompilingBoot() const;
-  bool RunningOnValgrind() const {
-    return running_on_valgrind_;
-  }
   bool HasImageSpace() const;
 
   ReferenceProcessor* GetReferenceProcessor() {
diff --git a/runtime/gc/reference_queue.h b/runtime/gc/reference_queue.h
index dbf4abc..4ef8478 100644
--- a/runtime/gc/reference_queue.h
+++ b/runtime/gc/reference_queue.h
@@ -24,7 +24,6 @@
 #include "atomic.h"
 #include "base/timing_logger.h"
 #include "globals.h"
-#include "gtest/gtest.h"
 #include "jni.h"
 #include "object_callbacks.h"
 #include "offsets.h"
@@ -45,44 +44,56 @@
 class ReferenceQueue {
  public:
   explicit ReferenceQueue(Mutex* lock);
+
   // Enqueue a reference if is not already enqueued. Thread safe to call from multiple threads
   // since it uses a lock to avoid a race between checking for the references presence and adding
   // it.
   void AtomicEnqueueIfNotEnqueued(Thread* self, mirror::Reference* ref)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
+
   // Enqueue a reference, unlike EnqueuePendingReference, enqueue reference checks that the
   // reference IsEnqueueable. Not thread safe, used when mutators are paused to minimize lock
   // overhead.
   void EnqueueReference(mirror::Reference* ref) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   void EnqueuePendingReference(mirror::Reference* ref) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   mirror::Reference* DequeuePendingReference() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Enqueues finalizer references with white referents.  White referents are blackened, moved to the
   // zombie field, and the referent field is cleared.
   void EnqueueFinalizerReferences(ReferenceQueue* cleared_references,
                                   IsHeapReferenceMarkedCallback* is_marked_callback,
                                   MarkObjectCallback* mark_object_callback, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Walks the reference list marking any references subject to the reference clearing policy.
   // References with a black referent are removed from the list.  References with white referents
   // biased toward saving are blackened and also removed from the list.
   void ForwardSoftReferences(IsHeapReferenceMarkedCallback* preserve_callback, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Unlink the reference list clearing references objects with white referents.  Cleared references
   // registered to a reference queue are scheduled for appending by the heap worker thread.
   void ClearWhiteReferences(ReferenceQueue* cleared_references,
                             IsHeapReferenceMarkedCallback* is_marked_callback, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   void Dump(std::ostream& os) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   bool IsEmpty() const {
     return list_ == nullptr;
   }
+
   void Clear() {
     list_ = nullptr;
   }
+
   mirror::Reference* GetList() {
     return list_;
   }
+
   // Visits list_, currently only used for the mark compact GC.
   void UpdateRoots(IsMarkedCallback* callback, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -90,10 +101,13 @@
  private:
   // Lock, used for parallel GC reference enqueuing. It allows for multiple threads simultaneously
   // calling AtomicEnqueueIfNotEnqueued.
-  Mutex* lock_;
+  Mutex* const lock_;
+
   // The actual reference list. Only a root for the mark compact GC since it will be null for other
   // GC types.
   mirror::Reference* list_;
+
+  DISALLOW_COPY_AND_ASSIGN(ReferenceQueue);
 };
 
 }  // namespace gc
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 452af90..d479038 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -21,6 +21,7 @@
 
 #include <random>
 
+#include "base/macros.h"
 #include "base/stl_util.h"
 #include "base/unix_file/fd_file.h"
 #include "base/scoped_flock.h"
@@ -118,7 +119,7 @@
                           std::string* error_msg) {
   const std::string boot_class_path_string(Runtime::Current()->GetBootClassPathString());
   std::vector<std::string> boot_class_path;
-  Split(boot_class_path_string, ':', boot_class_path);
+  Split(boot_class_path_string, ':', &boot_class_path);
   if (boot_class_path.empty()) {
     *error_msg = "Failed to generate image because no boot class path specified";
     return false;
diff --git a/runtime/gc/space/malloc_space.h b/runtime/gc/space/malloc_space.h
index 7230116..cfde460 100644
--- a/runtime/gc/space/malloc_space.h
+++ b/runtime/gc/space/malloc_space.h
@@ -19,7 +19,7 @@
 
 #include "space.h"
 
-#include <iostream>
+#include <ostream>
 #include <valgrind.h>
 #include <memcheck/memcheck.h>
 
diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc
index d25694a..161eba9 100644
--- a/runtime/gc/space/rosalloc_space.cc
+++ b/runtime/gc/space/rosalloc_space.cc
@@ -17,6 +17,9 @@
 
 #include "rosalloc_space-inl.h"
 
+#define ATRACE_TAG ATRACE_TAG_DALVIK
+#include "cutils/trace.h"
+
 #include "gc/accounting/card_table.h"
 #include "gc/accounting/space_bitmap-inl.h"
 #include "gc/heap.h"
@@ -73,8 +76,9 @@
   uint8_t* begin = mem_map->Begin();
   // TODO: Fix RosAllocSpace to support valgrind. There is currently some issues with
   // AllocationSize caused by redzones. b/12944686
-  if (false && Runtime::Current()->GetHeap()->RunningOnValgrind()) {
-    LOG(FATAL) << "Unimplemented";
+  if (Runtime::Current()->RunningOnValgrind()) {
+    UNIMPLEMENTED(FATAL);
+    UNREACHABLE();
   } else {
     return new RosAllocSpace(name, mem_map, rosalloc, begin, end, begin + capacity, growth_limit,
                              can_move_objects, starting_size, initial_size, low_memory_mode);
diff --git a/runtime/handle.h b/runtime/handle.h
index addb663..6af3220 100644
--- a/runtime/handle.h
+++ b/runtime/handle.h
@@ -20,6 +20,7 @@
 #include "base/casts.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/value_object.h"
 #include "stack.h"
 
 namespace art {
@@ -33,7 +34,7 @@
 // a wrap pointer. Handles are generally allocated within HandleScopes. Handle is a super-class
 // of MutableHandle and doesn't support assignment operations.
 template<class T>
-class Handle {
+class Handle : public ValueObject {
  public:
   Handle() : reference_(nullptr) {
   }
@@ -58,7 +59,7 @@
   }
 
   ALWAYS_INLINE T* Get() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return reference_->AsMirrorPtr();
+    return down_cast<T*>(reference_->AsMirrorPtr());
   }
 
   ALWAYS_INLINE jobject ToJObject() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -70,25 +71,25 @@
   }
 
  protected:
-  StackReference<T>* reference_;
-
   template<typename S>
   explicit Handle(StackReference<S>* reference)
-      : reference_(reinterpret_cast<StackReference<T>*>(reference)) {
+      : reference_(reference) {
   }
   template<typename S>
   explicit Handle(const Handle<S>& handle)
-      : reference_(reinterpret_cast<StackReference<T>*>(handle.reference_)) {
+      : reference_(handle.reference_) {
   }
 
-  StackReference<T>* GetReference() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE {
+  StackReference<mirror::Object>* GetReference() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE {
     return reference_;
   }
-  ALWAYS_INLINE const StackReference<T>* GetReference() const
+  ALWAYS_INLINE const StackReference<mirror::Object>* GetReference() const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return reference_;
   }
 
+  StackReference<mirror::Object>* reference_;
+
  private:
   friend class BuildGenericJniFrameVisitor;
   template<class S> friend class Handle;
@@ -121,8 +122,8 @@
   }
 
   ALWAYS_INLINE T* Assign(T* reference) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    StackReference<T>* ref = Handle<T>::GetReference();
-    T* const old = ref->AsMirrorPtr();
+    StackReference<mirror::Object>* ref = Handle<T>::GetReference();
+    T* old = down_cast<T*>(ref->AsMirrorPtr());
     ref->Assign(reference);
     return old;
   }
@@ -132,7 +133,6 @@
       : Handle<T>(handle) {
   }
 
- protected:
   template<typename S>
   explicit MutableHandle(StackReference<S>* reference) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       : Handle<T>(reference) {
@@ -153,7 +153,7 @@
   }
 
  private:
-  StackReference<T> null_ref_;
+  StackReference<mirror::Object> null_ref_;
 };
 
 }  // namespace art
diff --git a/runtime/handle_scope.h b/runtime/handle_scope.h
index f795e38..13c939f 100644
--- a/runtime/handle_scope.h
+++ b/runtime/handle_scope.h
@@ -159,7 +159,7 @@
   }
 
  private:
-  T** obj_;
+  T** const obj_;
 };
 
 // Scoped handle storage of a fixed size that is usually stack allocated.
@@ -169,19 +169,28 @@
   explicit StackHandleScope(Thread* self);
   ~StackHandleScope();
 
-  // Currently unused, using this GetReference instead of the one in HandleScope is preferred to
-  // avoid compiler optimizations incorrectly optimizing out of bound array accesses.
-  // TODO: Remove this when it is un-necessary.
-  ALWAYS_INLINE mirror::Object* GetReference(size_t i) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK_LT(i, kNumReferences);
-    return GetReferences()[i].AsMirrorPtr();
+  template<class T>
+  MutableHandle<T> NewHandle(T* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    SetReference(pos_, object);
+    MutableHandle<T> h(GetHandle<T>(pos_));
+    pos_++;
+    return h;
   }
 
-  ALWAYS_INLINE MutableHandle<mirror::Object> GetHandle(size_t i)
+  template<class T>
+  HandleWrapper<T> NewHandleWrapper(T** object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    SetReference(pos_, *object);
+    MutableHandle<T> h(GetHandle<T>(pos_));
+    pos_++;
+    return HandleWrapper<T>(object, h);
+  }
+
+ private:
+  template<class T>
+  ALWAYS_INLINE MutableHandle<T> GetHandle(size_t i)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK_LT(i, kNumReferences);
-    return MutableHandle<mirror::Object>(&GetReferences()[i]);
+    return MutableHandle<T>(&GetReferences()[i]);
   }
 
   ALWAYS_INLINE void SetReference(size_t i, mirror::Object* object)
@@ -190,23 +199,6 @@
     GetReferences()[i].Assign(object);
   }
 
-  template<class T>
-  MutableHandle<T> NewHandle(T* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    SetReference(pos_, object);
-    MutableHandle<T> h(GetHandle(pos_));
-    pos_++;
-    return h;
-  }
-
-  template<class T>
-  HandleWrapper<T> NewHandleWrapper(T** object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    SetReference(pos_, *object);
-    MutableHandle<T> h(GetHandle(pos_));
-    pos_++;
-    return HandleWrapper<T>(object, h);
-  }
-
- private:
   // Reference storage needs to be first as expected by the HandleScope layout.
   StackReference<mirror::Object> storage_[kNumReferences];
 
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index c1455fd..4d177a3 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -126,7 +126,7 @@
   }
   table_[index].Add(obj);
   result = ToIndirectRef(index);
-  if (false) {
+  if ((false)) {
     LOG(INFO) << "+++ added at " << ExtractIndex(result) << " top=" << segment_state_.parts.topIndex
               << " holes=" << segment_state_.parts.numHoles;
   }
@@ -193,7 +193,7 @@
     int numHoles = segment_state_.parts.numHoles - prevState.parts.numHoles;
     if (numHoles != 0) {
       while (--topIndex > bottomIndex && numHoles != 0) {
-        if (false) {
+        if ((false)) {
           LOG(INFO) << "+++ checking for hole at " << topIndex - 1
                     << " (cookie=" << cookie << ") val="
                     << table_[topIndex - 1].GetReference()->Read<kWithoutReadBarrier>();
@@ -201,7 +201,7 @@
         if (!table_[topIndex - 1].GetReference()->IsNull()) {
           break;
         }
-        if (false) {
+        if ((false)) {
           LOG(INFO) << "+++ ate hole at " << (topIndex - 1);
         }
         numHoles--;
@@ -210,7 +210,7 @@
       segment_state_.parts.topIndex = topIndex;
     } else {
       segment_state_.parts.topIndex = topIndex-1;
-      if (false) {
+      if ((false)) {
         LOG(INFO) << "+++ ate last entry " << topIndex - 1;
       }
     }
@@ -228,7 +228,7 @@
 
     *table_[idx].GetReference() = GcRoot<mirror::Object>(nullptr);
     segment_state_.parts.numHoles++;
-    if (false) {
+    if ((false)) {
       LOG(INFO) << "+++ left hole at " << idx << ", holes=" << segment_state_.parts.numHoles;
     }
   }
diff --git a/runtime/instruction_set.cc b/runtime/instruction_set.cc
index 644e055..0ca32fe 100644
--- a/runtime/instruction_set.cc
+++ b/runtime/instruction_set.cc
@@ -16,6 +16,13 @@
 
 #include "instruction_set.h"
 
+#include <signal.h>
+#include <fstream>
+
+#include "base/casts.h"
+#include "base/stringprintf.h"
+#include "utils.h"
+
 namespace art {
 
 const char* GetInstructionSetString(const InstructionSet isa) {
@@ -35,7 +42,7 @@
       return "none";
     default:
       LOG(FATAL) << "Unknown ISA " << isa;
-      return nullptr;
+      UNREACHABLE();
   }
 }
 
@@ -117,15 +124,385 @@
   }
 }
 
-std::string InstructionSetFeatures::GetFeatureString() const {
-  std::string result;
-  if ((mask_ & kHwDiv) != 0) {
-    result += "div";
+const InstructionSetFeatures* InstructionSetFeatures::FromVariant(InstructionSet isa,
+                                                                  const std::string& variant,
+                                                                  std::string* error_msg) {
+  const InstructionSetFeatures* result;
+  switch (isa) {
+    case kArm:
+    case kThumb2:
+      result = ArmInstructionSetFeatures::FromVariant(variant, error_msg);
+      break;
+    default:
+      result = UnknownInstructionSetFeatures::Unknown(isa);
+      break;
   }
-  if (result.size() == 0) {
-    result = "none";
+  CHECK_EQ(result == nullptr, error_msg->size() != 0);
+  return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::FromFeatureString(InstructionSet isa,
+                                                                        const std::string& feature_list,
+                                                                        std::string* error_msg) {
+  const InstructionSetFeatures* result;
+  switch (isa) {
+    case kArm:
+    case kThumb2:
+      result = ArmInstructionSetFeatures::FromFeatureString(feature_list, error_msg);
+      break;
+    default:
+      result = UnknownInstructionSetFeatures::Unknown(isa);
+      break;
+  }
+  // TODO: warn if feature_list doesn't agree with result's GetFeatureList().
+  CHECK_EQ(result == nullptr, error_msg->size() != 0);
+  return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::FromBitmap(InstructionSet isa,
+                                                                 uint32_t bitmap) {
+  const InstructionSetFeatures* result;
+  switch (isa) {
+    case kArm:
+    case kThumb2:
+      result = ArmInstructionSetFeatures::FromBitmap(bitmap);
+      break;
+    default:
+      result = UnknownInstructionSetFeatures::Unknown(isa);
+      break;
+  }
+  CHECK_EQ(bitmap, result->AsBitmap());
+  return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::FromCppDefines() {
+  const InstructionSetFeatures* result;
+  switch (kRuntimeISA) {
+    case kArm:
+    case kThumb2:
+      result = ArmInstructionSetFeatures::FromCppDefines();
+      break;
+    default:
+      result = UnknownInstructionSetFeatures::Unknown(kRuntimeISA);
+      break;
   }
   return result;
 }
 
+
+const InstructionSetFeatures* InstructionSetFeatures::FromCpuInfo() {
+  const InstructionSetFeatures* result;
+  switch (kRuntimeISA) {
+    case kArm:
+    case kThumb2:
+      result = ArmInstructionSetFeatures::FromCpuInfo();
+      break;
+    default:
+      result = UnknownInstructionSetFeatures::Unknown(kRuntimeISA);
+      break;
+  }
+  return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::FromHwcap() {
+  const InstructionSetFeatures* result;
+  switch (kRuntimeISA) {
+    case kArm:
+    case kThumb2:
+      result = ArmInstructionSetFeatures::FromHwcap();
+      break;
+    default:
+      result = UnknownInstructionSetFeatures::Unknown(kRuntimeISA);
+      break;
+  }
+  return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::FromAssembly() {
+  const InstructionSetFeatures* result;
+  switch (kRuntimeISA) {
+    case kArm:
+    case kThumb2:
+      result = ArmInstructionSetFeatures::FromAssembly();
+      break;
+    default:
+      result = UnknownInstructionSetFeatures::Unknown(kRuntimeISA);
+      break;
+  }
+  return result;
+}
+
+const ArmInstructionSetFeatures* InstructionSetFeatures::AsArmInstructionSetFeatures() const {
+  DCHECK_EQ(kArm, GetInstructionSet());
+  return down_cast<const ArmInstructionSetFeatures*>(this);
+}
+
+std::ostream& operator<<(std::ostream& os, const InstructionSetFeatures& rhs) {
+  os << "ISA: " << rhs.GetInstructionSet() << " Feature string: " << rhs.GetFeatureString();
+  return os;
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromFeatureString(
+    const std::string& feature_list, std::string* error_msg) {
+  std::vector<std::string> features;
+  Split(feature_list, ',', &features);
+  bool has_lpae = false;
+  bool has_div = false;
+  for (auto i = features.begin(); i != features.end(); i++) {
+    std::string feature = Trim(*i);
+    if (feature == "default" || feature == "none") {
+      // Nothing to do.
+    } else if (feature == "div") {
+      has_div = true;
+    } else if (feature == "nodiv") {
+      has_div = false;
+    } else if (feature == "lpae") {
+      has_lpae = true;
+    } else if (feature == "nolpae") {
+      has_lpae = false;
+    } else {
+      *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
+      return nullptr;
+    }
+  }
+  return new ArmInstructionSetFeatures(has_lpae, has_div);
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromVariant(
+    const std::string& variant, std::string* error_msg) {
+  // Look for variants that have divide support.
+  bool has_div = false;
+  {
+    static const char* arm_variants_with_div[] = {
+        "cortex-a7", "cortex-a12", "cortex-a15", "cortex-a17", "cortex-a53", "cortex-a57",
+        "cortex-m3", "cortex-m4", "cortex-r4", "cortex-r5",
+        "cyclone", "denver", "krait", "swift"
+    };
+    for (const char* div_variant : arm_variants_with_div) {
+      if (variant == div_variant) {
+        has_div = true;
+        break;
+      }
+    }
+  }
+  // Look for variants that have LPAE support.
+  bool has_lpae = false;
+  {
+    static const char* arm_variants_with_lpae[] = {
+        "cortex-a7", "cortex-a15", "krait", "denver"
+    };
+    for (const char* lpae_variant : arm_variants_with_lpae) {
+      if (variant == lpae_variant) {
+        has_lpae = true;
+        break;
+      }
+    }
+  }
+  if (has_div == false && has_lpae == false) {
+    // Avoid unsupported variants.
+    static const char* unsupported_arm_variants[] = {
+        // ARM processors that aren't ARMv7 compatible aren't supported.
+        "arm2", "arm250", "arm3", "arm6", "arm60", "arm600", "arm610", "arm620",
+        "cortex-m0", "cortex-m0plus", "cortex-m1",
+        "fa526", "fa626", "fa606te", "fa626te", "fmp626", "fa726te",
+        "iwmmxt", "iwmmxt2",
+        "strongarm", "strongarm110", "strongarm1100", "strongarm1110",
+        "xscale"
+    };
+    for (const char* us_variant : unsupported_arm_variants) {
+      if (variant == us_variant) {
+        *error_msg = StringPrintf("Attempt to use unsupported ARM variant: %s", us_variant);
+        return nullptr;
+      }
+    }
+    // Warn if the variant is unknown.
+    // TODO: some of the variants below may have feature support, but that support is currently
+    //       unknown so we'll choose conservative (sub-optimal) defaults without warning.
+    // TODO: some of the architectures may not support all features required by ART and should be
+    //       moved to unsupported_arm_variants[] above.
+    static const char* arm_variants_without_known_features[] = {
+        "arm7", "arm7m", "arm7d", "arm7dm", "arm7di", "arm7dmi", "arm70", "arm700", "arm700i",
+        "arm710", "arm710c", "arm7100", "arm720", "arm7500", "arm7500fe", "arm7tdmi", "arm7tdmi-s",
+        "arm710t", "arm720t", "arm740t",
+        "arm8", "arm810",
+        "arm9", "arm9e", "arm920", "arm920t", "arm922t", "arm946e-s", "arm966e-s", "arm968e-s",
+        "arm926ej-s", "arm940t", "arm9tdmi",
+        "arm10tdmi", "arm1020t", "arm1026ej-s", "arm10e", "arm1020e", "arm1022e",
+        "arm1136j-s", "arm1136jf-s",
+        "arm1156t2-s", "arm1156t2f-s", "arm1176jz-s", "arm1176jzf-s",
+        "cortex-a5", "cortex-a8", "cortex-a9", "cortex-a9-mp", "cortex-r4f",
+        "marvell-pj4", "mpcore", "mpcorenovfp"
+    };
+    bool found = false;
+    for (const char* ff_variant : arm_variants_without_known_features) {
+      if (variant == ff_variant) {
+        found = true;
+        break;
+      }
+    }
+    if (!found) {
+      LOG(WARNING) << "Unknown instruction set features for ARM CPU variant (" << variant
+          << ") using conservative defaults";
+    }
+  }
+  return new ArmInstructionSetFeatures(has_lpae, has_div);
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromBitmap(uint32_t bitmap) {
+  bool has_lpae = (bitmap & kLpaeBitfield) != 0;
+  bool has_div = (bitmap & kDivBitfield) != 0;
+  return new ArmInstructionSetFeatures(has_lpae, has_div);
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromCppDefines() {
+#if defined(__ARM_ARCH_EXT_IDIV__)
+  bool has_div = true;
+#else
+  bool has_div = false;
+#endif
+#if defined(__ARM_FEATURE_LPAE)
+  bool has_lpae = true;
+#else
+  bool has_lpae = false;
+#endif
+  return new ArmInstructionSetFeatures(has_lpae, has_div);
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromCpuInfo() {
+  // Look in /proc/cpuinfo for features we need.  Only use this when we can guarantee that
+  // the kernel puts the appropriate feature flags in here.  Sometimes it doesn't.
+  bool has_lpae = false;
+  bool has_div = false;
+
+  std::ifstream in("/proc/cpuinfo");
+  if (!in.fail()) {
+    while (!in.eof()) {
+      std::string line;
+      std::getline(in, line);
+      if (!in.eof()) {
+        LOG(INFO) << "cpuinfo line: " << line;
+        if (line.find("Features") != std::string::npos) {
+          LOG(INFO) << "found features";
+          if (line.find("idivt") != std::string::npos) {
+            // We always expect both ARM and Thumb divide instructions to be available or not
+            // available.
+            CHECK_NE(line.find("idiva"), std::string::npos);
+            has_div = true;
+          }
+          if (line.find("lpae") != std::string::npos) {
+            has_lpae = true;
+          }
+        }
+      }
+    }
+    in.close();
+  } else {
+    LOG(INFO) << "Failed to open /proc/cpuinfo";
+  }
+  return new ArmInstructionSetFeatures(has_lpae, has_div);
+}
+
+#if defined(HAVE_ANDROID_OS) && defined(__arm__)
+#include <sys/auxv.h>
+#include <asm/hwcap.h>
+#endif
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromHwcap() {
+  bool has_lpae = false;
+  bool has_div = false;
+
+#if defined(HAVE_ANDROID_OS) && defined(__arm__)
+  uint64_t hwcaps = getauxval(AT_HWCAP);
+  LOG(INFO) << "hwcaps=" << hwcaps;
+  if ((hwcaps & HWCAP_IDIVT) != 0) {
+    // We always expect both ARM and Thumb divide instructions to be available or not
+    // available.
+    CHECK_NE(hwcaps & HWCAP_IDIVA, 0U);
+    has_div = true;
+  }
+  if ((hwcaps & HWCAP_LPAE) != 0) {
+    has_lpae = true;
+  }
+#endif
+
+  return new ArmInstructionSetFeatures(has_lpae, has_div);
+}
+
+// A signal handler called by a fault for an illegal instruction.  We record the fact in r0
+// and then increment the PC in the signal context to return to the next instruction.  We know the
+// instruction is an sdiv (4 bytes long).
+static void bad_divide_inst_handle(int signo, siginfo_t* si, void* data) {
+  UNUSED(signo);
+  UNUSED(si);
+#if defined(__arm__)
+  struct ucontext *uc = (struct ucontext *)data;
+  struct sigcontext *sc = &uc->uc_mcontext;
+  sc->arm_r0 = 0;     // Set R0 to #0 to signal error.
+  sc->arm_pc += 4;    // Skip offending instruction.
+#else
+  UNUSED(data);
+#endif
+}
+
+#if defined(__arm__)
+extern "C" bool artCheckForARMSDIVInstruction();
+#endif
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromAssembly() {
+  // See if have a sdiv instruction.  Register a signal handler and try to execute an sdiv
+  // instruction.  If we get a SIGILL then it's not supported.
+  struct sigaction sa, osa;
+  sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
+  sa.sa_sigaction = bad_divide_inst_handle;
+  sigaction(SIGILL, &sa, &osa);
+
+  bool has_div = false;
+#if defined(__arm__)
+  if (artCheckForARMSDIVInstruction()) {
+    has_div = true;
+  }
+#endif
+
+  // Restore the signal handler.
+  sigaction(SIGILL, &osa, nullptr);
+
+  // Use compile time features to "detect" LPAE support.
+  // TODO: write an assembly LPAE support test.
+#if defined(__ARM_FEATURE_LPAE)
+  bool has_lpae = true;
+#else
+  bool has_lpae = false;
+#endif
+  return new ArmInstructionSetFeatures(has_lpae, has_div);
+}
+
+
+bool ArmInstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
+  if (kArm != other->GetInstructionSet()) {
+    return false;
+  }
+  const ArmInstructionSetFeatures* other_as_arm = other->AsArmInstructionSetFeatures();
+  return has_lpae_ == other_as_arm->has_lpae_ && has_div_ == other_as_arm->has_div_;
+}
+
+uint32_t ArmInstructionSetFeatures::AsBitmap() const {
+  return (has_lpae_ ? kLpaeBitfield : 0) | (has_div_ ? kDivBitfield : 0);
+}
+
+std::string ArmInstructionSetFeatures::GetFeatureString() const {
+  std::string result;
+  if (has_div_) {
+    result += ",div";
+  }
+  if (has_lpae_) {
+    result += ",lpae";
+  }
+  if (result.size() == 0) {
+    return "none";
+  } else {
+    // Strip leading comma.
+    return result.substr(1, result.size());
+  }
+}
+
 }  // namespace art
diff --git a/runtime/instruction_set.h b/runtime/instruction_set.h
index de6d0f4..529fa0c 100644
--- a/runtime/instruction_set.h
+++ b/runtime/instruction_set.h
@@ -22,6 +22,7 @@
 
 #include "base/logging.h"  // Logging is required for FATAL in the helper functions.
 #include "base/macros.h"
+#include "base/value_object.h"
 #include "globals.h"       // For KB.
 
 namespace art {
@@ -177,53 +178,163 @@
 
 size_t GetStackOverflowReservedBytes(InstructionSet isa);
 
-enum InstructionFeatures {
-  kHwDiv  = 0x1,              // Supports hardware divide.
-  kHwLpae = 0x2,              // Supports Large Physical Address Extension.
-};
+class ArmInstructionSetFeatures;
 
-// This is a bitmask of supported features per architecture.
-class PACKED(4) InstructionSetFeatures {
+// Abstraction used to describe features of a different instruction sets.
+class InstructionSetFeatures {
  public:
-  InstructionSetFeatures() : mask_(0) {}
-  explicit InstructionSetFeatures(uint32_t mask) : mask_(mask) {}
+  // Process a CPU variant string for the given ISA and create an InstructionSetFeatures.
+  static const InstructionSetFeatures* FromVariant(InstructionSet isa,
+                                                   const std::string& variant,
+                                                   std::string* error_msg);
 
-  static InstructionSetFeatures GuessInstructionSetFeatures();
+  // Parse a string of the form "div,lpae" and create an InstructionSetFeatures.
+  static const InstructionSetFeatures* FromFeatureString(InstructionSet isa,
+                                                         const std::string& feature_list,
+                                                         std::string* error_msg);
 
-  bool HasDivideInstruction() const {
-      return (mask_ & kHwDiv) != 0;
-  }
+  // Parse a bitmap for the given isa and create an InstructionSetFeatures.
+  static const InstructionSetFeatures* FromBitmap(InstructionSet isa, uint32_t bitmap);
 
-  void SetHasDivideInstruction(bool v) {
-    mask_ = (mask_ & ~kHwDiv) | (v ? kHwDiv : 0);
-  }
+  // Turn C pre-processor #defines into the equivalent instruction set features for kRuntimeISA.
+  static const InstructionSetFeatures* FromCppDefines();
 
-  bool HasLpae() const {
-    return (mask_ & kHwLpae) != 0;
-  }
+  // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+  static const InstructionSetFeatures* FromCpuInfo();
 
-  void SetHasLpae(bool v) {
-    mask_ = (mask_ & ~kHwLpae) | (v ? kHwLpae : 0);
-  }
+  // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+  // InstructionSetFeatures.
+  static const InstructionSetFeatures* FromHwcap();
 
-  std::string GetFeatureString() const;
+  // Use assembly tests of the current runtime (ie kRuntimeISA) to determine the
+  // InstructionSetFeatures. This works around kernel bugs in AT_HWCAP and /proc/cpuinfo.
+  static const InstructionSetFeatures* FromAssembly();
 
-  // Other features in here.
+  // Are these features the same as the other given features?
+  virtual bool Equals(const InstructionSetFeatures* other) const = 0;
 
-  bool operator==(const InstructionSetFeatures &peer) const {
-    return mask_ == peer.mask_;
-  }
+  // Return the ISA these features relate to.
+  virtual InstructionSet GetInstructionSet() const = 0;
 
-  bool operator!=(const InstructionSetFeatures &peer) const {
-    return mask_ != peer.mask_;
-  }
+  // Return a bitmap that represents the features. ISA specific.
+  virtual uint32_t AsBitmap() const = 0;
 
-  bool operator<=(const InstructionSetFeatures &peer) const {
-    return (mask_ & peer.mask_) == mask_;
-  }
+  // Return a string of the form "div,lpae" or "none".
+  virtual std::string GetFeatureString() const = 0;
+
+  // Down cast this ArmInstructionFeatures.
+  const ArmInstructionSetFeatures* AsArmInstructionSetFeatures() const;
+
+  virtual ~InstructionSetFeatures() {}
+
+ protected:
+  InstructionSetFeatures() {}
 
  private:
-  uint32_t mask_;
+  DISALLOW_COPY_AND_ASSIGN(InstructionSetFeatures);
+};
+std::ostream& operator<<(std::ostream& os, const InstructionSetFeatures& rhs);
+
+// Instruction set features relevant to the ARM architecture.
+class ArmInstructionSetFeatures FINAL : public InstructionSetFeatures {
+ public:
+  // Process a CPU variant string like "krait" or "cortex-a15" and create InstructionSetFeatures.
+  static const ArmInstructionSetFeatures* FromVariant(const std::string& variant,
+                                                      std::string* error_msg);
+
+  // Parse a string of the form "div,lpae" and create an InstructionSetFeatures.
+  static const ArmInstructionSetFeatures* FromFeatureString(const std::string& feature_list,
+                                                            std::string* error_msg);
+
+  // Parse a bitmap and create an InstructionSetFeatures.
+  static const ArmInstructionSetFeatures* FromBitmap(uint32_t bitmap);
+
+  // Turn C pre-processor #defines into the equivalent instruction set features.
+  static const ArmInstructionSetFeatures* FromCppDefines();
+
+  // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+  static const ArmInstructionSetFeatures* FromCpuInfo();
+
+  // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+  // InstructionSetFeatures.
+  static const ArmInstructionSetFeatures* FromHwcap();
+
+  // Use assembly tests of the current runtime (ie kRuntimeISA) to determine the
+  // InstructionSetFeatures. This works around kernel bugs in AT_HWCAP and /proc/cpuinfo.
+  static const ArmInstructionSetFeatures* FromAssembly();
+
+  bool Equals(const InstructionSetFeatures* other) const OVERRIDE;
+
+  InstructionSet GetInstructionSet() const OVERRIDE {
+    return kArm;
+  }
+
+  uint32_t AsBitmap() const OVERRIDE;
+
+  // Return a string of the form "div,lpae" or "none".
+  std::string GetFeatureString() const OVERRIDE;
+
+  // Is the divide instruction feature enabled?
+  bool HasDivideInstruction() const {
+      return has_div_;
+  }
+
+  // Is the Large Physical Address Extension (LPAE) instruction feature enabled? When true code can
+  // be used that assumes double register loads and stores (ldrd, strd) don't tear.
+  bool HasLpae() const {
+    return has_lpae_;
+  }
+
+  virtual ~ArmInstructionSetFeatures() {}
+
+ private:
+  ArmInstructionSetFeatures(bool has_lpae, bool has_div)
+      : has_lpae_(has_lpae), has_div_(has_div) {
+  }
+
+  // Bitmap positions for encoding features as a bitmap.
+  enum {
+    kDivBitfield = 1,
+    kLpaeBitfield = 2,
+  };
+
+  const bool has_lpae_;
+  const bool has_div_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArmInstructionSetFeatures);
+};
+
+// A class used for instruction set features on ISAs that don't yet have any features defined.
+class UnknownInstructionSetFeatures FINAL : public InstructionSetFeatures {
+ public:
+  static const UnknownInstructionSetFeatures* Unknown(InstructionSet isa) {
+    return new UnknownInstructionSetFeatures(isa);
+  }
+
+  bool Equals(const InstructionSetFeatures* other) const OVERRIDE {
+    return isa_ == other->GetInstructionSet();
+  }
+
+  InstructionSet GetInstructionSet() const OVERRIDE {
+    return isa_;
+  }
+
+  uint32_t AsBitmap() const OVERRIDE {
+    return 0;
+  }
+
+  std::string GetFeatureString() const OVERRIDE {
+    return "none";
+  }
+
+  virtual ~UnknownInstructionSetFeatures() {}
+
+ private:
+  explicit UnknownInstructionSetFeatures(InstructionSet isa) : isa_(isa) {}
+
+  const InstructionSet isa_;
+
+  DISALLOW_COPY_AND_ASSIGN(UnknownInstructionSetFeatures);
 };
 
 // The following definitions create return types for two word-sized entities that will be passed
diff --git a/runtime/instruction_set_test.cc b/runtime/instruction_set_test.cc
index 80191b1..3f2d16b 100644
--- a/runtime/instruction_set_test.cc
+++ b/runtime/instruction_set_test.cc
@@ -16,6 +16,7 @@
 
 #include "instruction_set.h"
 
+#include "base/stringprintf.h"
 #include "common_runtime_test.h"
 
 namespace art {
@@ -50,4 +51,229 @@
   EXPECT_EQ(sizeof(void*), GetInstructionSetPointerSize(kRuntimeISA));
 }
 
+TEST_F(InstructionSetTest, X86Features) {
+  // Build features for a 32-bit x86 atom processor.
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> x86_features(
+      InstructionSetFeatures::FromVariant(kX86, "atom", &error_msg));
+  ASSERT_TRUE(x86_features.get() != nullptr) << error_msg;
+  EXPECT_EQ(x86_features->GetInstructionSet(), kX86);
+  EXPECT_TRUE(x86_features->Equals(x86_features.get()));
+  EXPECT_STREQ("none", x86_features->GetFeatureString().c_str());
+  EXPECT_EQ(x86_features->AsBitmap(), 0U);
+
+  // Build features for a 32-bit x86 default processor.
+  std::unique_ptr<const InstructionSetFeatures> x86_default_features(
+      InstructionSetFeatures::FromFeatureString(kX86, "default", &error_msg));
+  ASSERT_TRUE(x86_default_features.get() != nullptr) << error_msg;
+  EXPECT_EQ(x86_default_features->GetInstructionSet(), kX86);
+  EXPECT_TRUE(x86_default_features->Equals(x86_default_features.get()));
+  EXPECT_STREQ("none", x86_default_features->GetFeatureString().c_str());
+  EXPECT_EQ(x86_default_features->AsBitmap(), 0U);
+
+  // Build features for a 64-bit x86-64 atom processor.
+  std::unique_ptr<const InstructionSetFeatures> x86_64_features(
+      InstructionSetFeatures::FromVariant(kX86_64, "atom", &error_msg));
+  ASSERT_TRUE(x86_64_features.get() != nullptr) << error_msg;
+  EXPECT_EQ(x86_64_features->GetInstructionSet(), kX86_64);
+  EXPECT_TRUE(x86_64_features->Equals(x86_64_features.get()));
+  EXPECT_STREQ("none", x86_64_features->GetFeatureString().c_str());
+  EXPECT_EQ(x86_64_features->AsBitmap(), 0U);
+
+  EXPECT_FALSE(x86_64_features->Equals(x86_features.get()));
+  EXPECT_FALSE(x86_64_features->Equals(x86_default_features.get()));
+  EXPECT_TRUE(x86_features->Equals(x86_default_features.get()));
+}
+
+TEST_F(InstructionSetTest, ArmFeaturesFromVariant) {
+  // Build features for a 32-bit ARM krait processor.
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> krait_features(
+      InstructionSetFeatures::FromVariant(kArm, "krait", &error_msg));
+  ASSERT_TRUE(krait_features.get() != nullptr) << error_msg;
+
+  ASSERT_EQ(krait_features->GetInstructionSet(), kArm);
+  EXPECT_TRUE(krait_features->Equals(krait_features.get()));
+  EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+  EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasLpae());
+  EXPECT_STREQ("div,lpae", krait_features->GetFeatureString().c_str());
+  EXPECT_EQ(krait_features->AsBitmap(), 3U);
+
+  // Build features for a 32-bit ARM denver processor.
+  std::unique_ptr<const InstructionSetFeatures> denver_features(
+      InstructionSetFeatures::FromVariant(kArm, "denver", &error_msg));
+  ASSERT_TRUE(denver_features.get() != nullptr) << error_msg;
+
+  EXPECT_TRUE(denver_features->Equals(denver_features.get()));
+  EXPECT_TRUE(denver_features->Equals(krait_features.get()));
+  EXPECT_TRUE(krait_features->Equals(denver_features.get()));
+  EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+  EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasLpae());
+  EXPECT_STREQ("div,lpae", denver_features->GetFeatureString().c_str());
+  EXPECT_EQ(denver_features->AsBitmap(), 3U);
+
+  // Build features for a 32-bit ARMv7 processor.
+  std::unique_ptr<const InstructionSetFeatures> arm7_features(
+      InstructionSetFeatures::FromVariant(kArm, "arm7", &error_msg));
+  ASSERT_TRUE(arm7_features.get() != nullptr) << error_msg;
+
+  EXPECT_TRUE(arm7_features->Equals(arm7_features.get()));
+  EXPECT_FALSE(arm7_features->Equals(krait_features.get()));
+  EXPECT_FALSE(krait_features->Equals(arm7_features.get()));
+  EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+  EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasLpae());
+  EXPECT_STREQ("none", arm7_features->GetFeatureString().c_str());
+  EXPECT_EQ(arm7_features->AsBitmap(), 0U);
+
+  // ARM6 is not a supported architecture variant.
+  std::unique_ptr<const InstructionSetFeatures> arm6_features(
+      InstructionSetFeatures::FromVariant(kArm, "arm6", &error_msg));
+  EXPECT_TRUE(arm6_features.get() == nullptr);
+  EXPECT_NE(error_msg.size(), 0U);
+}
+
+TEST_F(InstructionSetTest, ArmFeaturesFromString) {
+  // Build features for a 32-bit ARM with LPAE and div processor.
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> krait_features(
+      InstructionSetFeatures::FromFeatureString(kArm, "lpae,div", &error_msg));
+  ASSERT_TRUE(krait_features.get() != nullptr) << error_msg;
+
+  ASSERT_EQ(krait_features->GetInstructionSet(), kArm);
+  EXPECT_TRUE(krait_features->Equals(krait_features.get()));
+  EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+  EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasLpae());
+  EXPECT_STREQ("div,lpae", krait_features->GetFeatureString().c_str());
+  EXPECT_EQ(krait_features->AsBitmap(), 3U);
+
+  // Build features for a 32-bit ARM processor with LPAE and div flipped.
+  std::unique_ptr<const InstructionSetFeatures> denver_features(
+      InstructionSetFeatures::FromFeatureString(kArm, "div,lpae", &error_msg));
+  ASSERT_TRUE(denver_features.get() != nullptr) << error_msg;
+
+  EXPECT_TRUE(denver_features->Equals(denver_features.get()));
+  EXPECT_TRUE(denver_features->Equals(krait_features.get()));
+  EXPECT_TRUE(krait_features->Equals(denver_features.get()));
+  EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+  EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasLpae());
+  EXPECT_STREQ("div,lpae", denver_features->GetFeatureString().c_str());
+  EXPECT_EQ(denver_features->AsBitmap(), 3U);
+
+  // Build features for a 32-bit default ARM processor.
+  std::unique_ptr<const InstructionSetFeatures> arm7_features(
+      InstructionSetFeatures::FromFeatureString(kArm, "default", &error_msg));
+  ASSERT_TRUE(arm7_features.get() != nullptr) << error_msg;
+
+  EXPECT_TRUE(arm7_features->Equals(arm7_features.get()));
+  EXPECT_FALSE(arm7_features->Equals(krait_features.get()));
+  EXPECT_FALSE(krait_features->Equals(arm7_features.get()));
+  EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+  EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasLpae());
+  EXPECT_STREQ("none", arm7_features->GetFeatureString().c_str());
+  EXPECT_EQ(arm7_features->AsBitmap(), 0U);
+}
+
+#ifdef HAVE_ANDROID_OS
+#include "cutils/properties.h"
+
+TEST_F(InstructionSetTest, FeaturesFromSystemPropertyVariant) {
+  // Take the default set of instruction features from the build.
+  std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+      InstructionSetFeatures::FromCppDefines());
+
+  // Read the features property.
+  std::string key = StringPrintf("dalvik.vm.isa.%s.variant", GetInstructionSetString(kRuntimeISA));
+  char dex2oat_isa_variant[PROPERTY_VALUE_MAX];
+  if (property_get(key.c_str(), dex2oat_isa_variant, nullptr) > 0) {
+    // Use features from property to build InstructionSetFeatures and check against build's
+    // features.
+    std::string error_msg;
+    std::unique_ptr<const InstructionSetFeatures> property_features(
+        InstructionSetFeatures::FromVariant(kRuntimeISA, dex2oat_isa_variant, &error_msg));
+    ASSERT_TRUE(property_features.get() != nullptr) << error_msg;
+
+    EXPECT_TRUE(property_features->Equals(instruction_set_features.get()))
+      << "System property features: " << *property_features.get()
+      << "\nFeatures from build: " << *instruction_set_features.get();
+  }
+}
+
+TEST_F(InstructionSetTest, FeaturesFromSystemPropertyString) {
+  // Take the default set of instruction features from the build.
+  std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+      InstructionSetFeatures::FromCppDefines());
+
+  // Read the features property.
+  std::string key = StringPrintf("dalvik.vm.isa.%s.features", GetInstructionSetString(kRuntimeISA));
+  char dex2oat_isa_features[PROPERTY_VALUE_MAX];
+  if (property_get(key.c_str(), dex2oat_isa_features, nullptr) > 0) {
+    // Use features from property to build InstructionSetFeatures and check against build's
+    // features.
+    std::string error_msg;
+    std::unique_ptr<const InstructionSetFeatures> property_features(
+        InstructionSetFeatures::FromFeatureString(kRuntimeISA, dex2oat_isa_features, &error_msg));
+    ASSERT_TRUE(property_features.get() != nullptr) << error_msg;
+
+    EXPECT_TRUE(property_features->Equals(instruction_set_features.get()))
+      << "System property features: " << *property_features.get()
+      << "\nFeatures from build: " << *instruction_set_features.get();
+  }
+}
+#endif
+
+#if defined(__arm__)
+TEST_F(InstructionSetTest, DISABLED_FeaturesFromCpuInfo) {
+  LOG(WARNING) << "Test disabled due to buggy ARM kernels";
+#else
+TEST_F(InstructionSetTest, FeaturesFromCpuInfo) {
+#endif
+  // Take the default set of instruction features from the build.
+  std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+      InstructionSetFeatures::FromCppDefines());
+
+  // Check we get the same instruction set features using /proc/cpuinfo.
+  std::unique_ptr<const InstructionSetFeatures> cpuinfo_features(
+      InstructionSetFeatures::FromCpuInfo());
+  EXPECT_TRUE(cpuinfo_features->Equals(instruction_set_features.get()))
+      << "CPU Info features: " << *cpuinfo_features.get()
+      << "\nFeatures from build: " << *instruction_set_features.get();
+}
+
+#if defined(__arm__)
+TEST_F(InstructionSetTest, DISABLED_FeaturesFromHwcap) {
+  LOG(WARNING) << "Test disabled due to buggy ARM kernels";
+#else
+TEST_F(InstructionSetTest, FeaturesFromHwcap) {
+#endif
+  // Take the default set of instruction features from the build.
+  std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+      InstructionSetFeatures::FromCppDefines());
+
+  // Check we get the same instruction set features using AT_HWCAP.
+  std::unique_ptr<const InstructionSetFeatures> hwcap_features(
+      InstructionSetFeatures::FromHwcap());
+  EXPECT_TRUE(hwcap_features->Equals(instruction_set_features.get()))
+      << "Hwcap features: " << *hwcap_features.get()
+      << "\nFeatures from build: " << *instruction_set_features.get();
+}
+
+
+#if defined(__arm__)
+TEST_F(InstructionSetTest, DISABLED_FeaturesFromAssembly) {
+  LOG(WARNING) << "Test disabled due to buggy ARM kernels";
+#else
+TEST_F(InstructionSetTest, FeaturesFromAssembly) {
+#endif
+  // Take the default set of instruction features from the build.
+  std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+      InstructionSetFeatures::FromCppDefines());
+
+  // Check we get the same instruction set features using assembly tests.
+  std::unique_ptr<const InstructionSetFeatures> assembly_features(
+      InstructionSetFeatures::FromAssembly());
+  EXPECT_TRUE(assembly_features->Equals(instruction_set_features.get()))
+      << "Assembly features: " << *assembly_features.get()
+      << "\nFeatures from build: " << *instruction_set_features.get();
+}
+
 }  // namespace art
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 15be6b7..fc3da36 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -18,13 +18,17 @@
 
 #include <sys/uio.h>
 
+#include <sstream>
+
 #include "arch/context.h"
 #include "atomic.h"
 #include "base/unix_file/fd_file.h"
 #include "class_linker.h"
 #include "debugger.h"
 #include "dex_file-inl.h"
+#include "entrypoints/quick/quick_entrypoints.h"
 #include "entrypoints/quick/quick_alloc_entrypoints.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
 #include "gc_root-inl.h"
 #include "interpreter/interpreter.h"
 #include "mirror/art_method-inl.h"
@@ -33,9 +37,6 @@
 #include "mirror/object_array-inl.h"
 #include "mirror/object-inl.h"
 #include "nth_caller_visitor.h"
-#if !defined(ART_USE_PORTABLE_COMPILER)
-#include "entrypoints/quick/quick_entrypoints.h"
-#endif
 #include "os.h"
 #include "scoped_thread_state_change.h"
 #include "thread.h"
@@ -95,21 +96,20 @@
   }
   if (!method->IsResolutionMethod()) {
     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-    if (quick_code == GetQuickToInterpreterBridge() ||
-        quick_code == class_linker->GetQuickToInterpreterBridgeTrampoline() ||
-        (quick_code == class_linker->GetQuickResolutionTrampoline() &&
-         Runtime::Current()->GetInstrumentation()->IsForcedInterpretOnly()
-         && !method->IsNative() && !method->IsProxyMethod())) {
+    if (class_linker->IsQuickToInterpreterBridge(quick_code) ||
+        (class_linker->IsQuickResolutionStub(quick_code) &&
+         Runtime::Current()->GetInstrumentation()->IsForcedInterpretOnly() &&
+         !method->IsNative() && !method->IsProxyMethod())) {
       if (kIsDebugBuild) {
         if (quick_code == GetQuickToInterpreterBridge()) {
           DCHECK(portable_code == GetPortableToInterpreterBridge());
-        } else if (quick_code == class_linker->GetQuickResolutionTrampoline()) {
-          DCHECK(portable_code == class_linker->GetPortableResolutionTrampoline());
+        } else if (class_linker->IsQuickResolutionStub(quick_code)) {
+          DCHECK(class_linker->IsPortableResolutionStub(portable_code));
         }
       }
       DCHECK(!method->IsNative()) << PrettyMethod(method);
       DCHECK(!method->IsProxyMethod()) << PrettyMethod(method);
-      method->SetEntryPointFromInterpreter(art::interpreter::artInterpreterToInterpreterBridge);
+      method->SetEntryPointFromInterpreter(art::artInterpreterToInterpreterBridge);
     } else {
       method->SetEntryPointFromInterpreter(art::artInterpreterToCompiledCodeBridge);
     }
@@ -140,8 +140,8 @@
       new_portable_code = class_linker->GetPortableOatCodeFor(method, &have_portable_code);
       new_quick_code = class_linker->GetQuickOatCodeFor(method);
     } else {
-      new_portable_code = class_linker->GetPortableResolutionTrampoline();
-      new_quick_code = class_linker->GetQuickResolutionTrampoline();
+      new_portable_code = GetPortableResolutionStub();
+      new_quick_code = GetQuickResolutionStub();
     }
   } else {  // !uninstall
     if ((interpreter_stubs_installed_ || forced_interpret_only_ || IsDeoptimized(method)) &&
@@ -159,11 +159,11 @@
         } else {
           new_portable_code = class_linker->GetPortableOatCodeFor(method, &have_portable_code);
           new_quick_code = class_linker->GetQuickOatCodeFor(method);
-          DCHECK(new_quick_code != class_linker->GetQuickToInterpreterBridgeTrampoline());
+          DCHECK(!class_linker->IsQuickToInterpreterBridge(new_quick_code));
         }
       } else {
-        new_portable_code = class_linker->GetPortableResolutionTrampoline();
-        new_quick_code = class_linker->GetQuickResolutionTrampoline();
+        new_portable_code = GetPortableResolutionStub();
+        new_quick_code = GetQuickResolutionStub();
       }
     }
   }
@@ -287,7 +287,7 @@
 
   Instrumentation* instrumentation = reinterpret_cast<Instrumentation*>(arg);
   std::unique_ptr<Context> context(Context::Create());
-  uintptr_t instrumentation_exit_pc = GetQuickInstrumentationExitPc();
+  uintptr_t instrumentation_exit_pc = reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc());
   InstallStackVisitor visitor(thread, context.get(), instrumentation_exit_pc);
   visitor.WalkStack(true);
   CHECK_EQ(visitor.dex_pcs_.size(), thread->GetInstrumentationStack()->size());
@@ -388,7 +388,8 @@
   std::deque<instrumentation::InstrumentationStackFrame>* stack = thread->GetInstrumentationStack();
   if (stack->size() > 0) {
     Instrumentation* instrumentation = reinterpret_cast<Instrumentation*>(arg);
-    uintptr_t instrumentation_exit_pc = GetQuickInstrumentationExitPc();
+    uintptr_t instrumentation_exit_pc =
+        reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc());
     RestoreStackVisitor visitor(thread, instrumentation_exit_pc, instrumentation);
     visitor.WalkStack(true);
     CHECK_EQ(visitor.frames_removed_, stack->size());
@@ -632,7 +633,6 @@
     SetEntrypointsInstrumented(true);
   }
   ++quick_alloc_entry_points_instrumentation_counter_;
-  LOG(INFO) << "Counter: " << quick_alloc_entry_points_instrumentation_counter_;
 }
 
 void Instrumentation::UninstrumentQuickAllocEntryPointsLocked() {
@@ -642,7 +642,6 @@
   if (quick_alloc_entry_points_instrumentation_counter_ == 0) {
     SetEntrypointsInstrumented(false);
   }
-  LOG(INFO) << "Counter: " << quick_alloc_entry_points_instrumentation_counter_;
 }
 
 void Instrumentation::ResetQuickAllocEntryPoints() {
@@ -669,11 +668,10 @@
       new_have_portable_code = false;
     } else {
       ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-      if (quick_code == class_linker->GetQuickResolutionTrampoline() ||
-          quick_code == class_linker->GetQuickToInterpreterBridgeTrampoline() ||
-          quick_code == GetQuickToInterpreterBridge()) {
-        DCHECK((portable_code == class_linker->GetPortableResolutionTrampoline()) ||
-               (portable_code == GetPortableToInterpreterBridge()));
+      if (class_linker->IsQuickResolutionStub(quick_code) ||
+          class_linker->IsQuickToInterpreterBridge(quick_code)) {
+        DCHECK(class_linker->IsPortableResolutionStub(portable_code) ||
+               class_linker->IsPortableToInterpreterBridge(portable_code));
         new_portable_code = portable_code;
         new_quick_code = quick_code;
         new_have_portable_code = have_portable_code;
@@ -793,9 +791,7 @@
     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
     if (method->IsStatic() && !method->IsConstructor() &&
         !method->GetDeclaringClass()->IsInitialized()) {
-      // TODO: we're updating to entrypoints in the image here, we can avoid the trampoline.
-      UpdateEntrypoints(method, class_linker->GetQuickResolutionTrampoline(),
-                        class_linker->GetPortableResolutionTrampoline(), false);
+      UpdateEntrypoints(method, GetQuickResolutionStub(), GetPortableResolutionStub(), false);
     } else {
       bool have_portable_code = false;
       const void* quick_code = class_linker->GetQuickOatCodeFor(method);
@@ -877,9 +873,10 @@
     const void* code = method->GetEntryPointFromQuickCompiledCode();
     DCHECK(code != nullptr);
     ClassLinker* class_linker = runtime->GetClassLinker();
-    if (LIKELY(code != class_linker->GetQuickResolutionTrampoline()) &&
-        LIKELY(code != class_linker->GetQuickToInterpreterBridgeTrampoline()) &&
-        LIKELY(code != GetQuickToInterpreterBridge())) {
+    if (LIKELY(!class_linker->IsQuickResolutionStub(code) &&
+               !class_linker->IsQuickToInterpreterBridge(code)) &&
+               !class_linker->IsQuickResolutionStub(code) &&
+               !class_linker->IsQuickToInterpreterBridge(code)) {
       return code;
     }
   }
@@ -1017,6 +1014,7 @@
   // Set return PC and check the sanity of the stack.
   *return_pc = instrumentation_frame.return_pc_;
   CheckStackDepth(self, instrumentation_frame, 0);
+  self->VerifyStack();
 
   mirror::ArtMethod* method = instrumentation_frame.method_;
   uint32_t length;
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 8fb1712..dfb03cd 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -507,8 +507,9 @@
   ret_val->SetJ(value.GetJ());
 }
 
-JValue EnterInterpreterFromStub(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
-                                ShadowFrame& shadow_frame) {
+JValue EnterInterpreterFromEntryPoint(Thread* self, MethodHelper* mh,
+                                      const DexFile::CodeItem* code_item,
+                                      ShadowFrame* shadow_frame) {
   DCHECK_EQ(self, Thread::Current());
   bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks();
   if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEndForInterpreter(implicit_check))) {
@@ -516,10 +517,10 @@
     return JValue();
   }
 
-  return Execute(self, mh, code_item, shadow_frame, JValue());
+  return Execute(self, *mh, code_item, *shadow_frame, JValue());
 }
 
-extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh,
+extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper* mh,
                                                   const DexFile::CodeItem* code_item,
                                                   ShadowFrame* shadow_frame, JValue* result) {
   bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks();
@@ -529,10 +530,10 @@
   }
 
   self->PushShadowFrame(shadow_frame);
-  DCHECK_EQ(shadow_frame->GetMethod(), mh.Get());
+  DCHECK_EQ(shadow_frame->GetMethod(), mh->Get());
   // Ensure static methods are initialized.
-  if (mh.Get()->IsStatic()) {
-    mirror::Class* declaring_class = mh.Get()->GetDeclaringClass();
+  if (mh->Get()->IsStatic()) {
+    mirror::Class* declaring_class = mh->Get()->GetDeclaringClass();
     if (UNLIKELY(!declaring_class->IsInitialized())) {
       StackHandleScope<1> hs(self);
       HandleWrapper<Class> h_declaring_class(hs.NewHandleWrapper(&declaring_class));
@@ -546,15 +547,15 @@
     }
   }
 
-  if (LIKELY(!mh.Get()->IsNative())) {
-    result->SetJ(Execute(self, mh, code_item, *shadow_frame, JValue()).GetJ());
+  if (LIKELY(!mh->Get()->IsNative())) {
+    result->SetJ(Execute(self, *mh, code_item, *shadow_frame, JValue()).GetJ());
   } else {
     // We don't expect to be asked to interpret native code (which is entered via a JNI compiler
     // generated stub) except during testing and image writing.
     CHECK(!Runtime::Current()->IsStarted());
-    Object* receiver = mh.Get()->IsStatic() ? nullptr : shadow_frame->GetVRegReference(0);
-    uint32_t* args = shadow_frame->GetVRegArgs(mh.Get()->IsStatic() ? 0 : 1);
-    UnstartedRuntimeJni(self, mh.Get(), receiver, args, result);
+    Object* receiver = mh->Get()->IsStatic() ? nullptr : shadow_frame->GetVRegReference(0);
+    uint32_t* args = shadow_frame->GetVRegArgs(mh->Get()->IsStatic() ? 0 : 1);
+    UnstartedRuntimeJni(self, mh->Get(), receiver, args, result);
   }
 
   self->PopShadowFrame();
diff --git a/runtime/interpreter/interpreter.h b/runtime/interpreter/interpreter.h
index 0750eb5..d327a71 100644
--- a/runtime/interpreter/interpreter.h
+++ b/runtime/interpreter/interpreter.h
@@ -42,19 +42,20 @@
                                            JValue* ret_val)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-extern JValue EnterInterpreterFromStub(Thread* self, MethodHelper& mh,
-                                       const DexFile::CodeItem* code_item,
-                                       ShadowFrame& shadow_frame)
+extern JValue EnterInterpreterFromEntryPoint(Thread* self, MethodHelper* mh,
+                                             const DexFile::CodeItem* code_item,
+                                             ShadowFrame* shadow_frame)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh,
+
+}  // namespace interpreter
+
+extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper* mh,
                                                   const DexFile::CodeItem* code_item,
                                                   ShadowFrame* shadow_frame, JValue* result)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-}  // namespace interpreter
-
-extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh,
+extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper* mh,
                                                    const DexFile::CodeItem* code_item,
                                                    ShadowFrame* shadow_frame, JValue* result)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 52583ae..3ccdd03 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -506,7 +506,7 @@
   exit(0);  // Unreachable, keep GCC happy.
 }
 
-static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh,
+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_);
@@ -666,9 +666,9 @@
         mh.Get()->GetEntryPointFromInterpreter() == artInterpreterToCompiledCodeBridge) {
       LOG(FATAL) << "Attempt to call compiled code when -Xint: " << PrettyMethod(mh.Get());
     }
-    (mh.Get()->GetEntryPointFromInterpreter())(self, mh, code_item, new_shadow_frame, result);
+    (mh.Get()->GetEntryPointFromInterpreter())(self, &mh, code_item, new_shadow_frame, result);
   } else {
-    UnstartedRuntimeInvoke(self, mh, code_item, new_shadow_frame, result, first_dest_reg);
+    UnstartedRuntimeInvoke(self, &mh, code_item, new_shadow_frame, result, first_dest_reg);
   }
   return !self->IsExceptionPending();
 }
@@ -809,7 +809,7 @@
   result->SetL(found);
 }
 
-static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh,
+static void UnstartedRuntimeInvoke(Thread* self, MethodHelper* mh,
                                    const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame,
                                    JValue* result, size_t arg_offset) {
   // In a runtime that's not started we intercept certain methods to avoid complicated dependency
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index a8345ad..fa03fc7 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -21,6 +21,9 @@
 
 #include <math.h>
 
+#include <iostream>
+#include <sstream>
+
 #include "base/logging.h"
 #include "class_linker-inl.h"
 #include "common_throws.h"
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index 1444d97..19e03d8 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -18,9 +18,11 @@
 
 #include <dlfcn.h>
 
+#include "base/dumpable.h"
 #include "base/mutex.h"
 #include "base/stl_util.h"
 #include "check_jni.h"
+#include "fault_handler.h"
 #include "indirect_reference_table-inl.h"
 #include "mirror/art_method.h"
 #include "mirror/class-inl.h"
@@ -688,6 +690,10 @@
     JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym);
     int version = (*jni_on_load)(this, nullptr);
 
+    if (runtime_->GetTargetSdkVersion() != 0 && runtime_->GetTargetSdkVersion() <= 21) {
+      fault_manager.EnsureArtActionInFrontOfSignalChain();
+    }
+
     self->SetClassLoaderOverride(old_class_loader.get());
 
     if (version == JNI_ERR) {
diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc
index 16a774f..7fdc18e 100644
--- a/runtime/jdwp/jdwp_handler.cc
+++ b/runtime/jdwp/jdwp_handler.cc
@@ -329,14 +329,14 @@
   expandBufAddUtf8String(pReply, "/");
 
   std::vector<std::string> class_path;
-  Split(Runtime::Current()->GetClassPathString(), ':', class_path);
+  Split(Runtime::Current()->GetClassPathString(), ':', &class_path);
   expandBufAdd4BE(pReply, class_path.size());
   for (size_t i = 0; i < class_path.size(); ++i) {
     expandBufAddUtf8String(pReply, class_path[i]);
   }
 
   std::vector<std::string> boot_class_path;
-  Split(Runtime::Current()->GetBootClassPathString(), ':', boot_class_path);
+  Split(Runtime::Current()->GetBootClassPathString(), ':', &boot_class_path);
   expandBufAdd4BE(pReply, boot_class_path.size());
   for (size_t i = 0; i < boot_class_path.size(); ++i) {
     expandBufAddUtf8String(pReply, boot_class_path[i]);
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index dea3014..ad06b85 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -30,6 +30,7 @@
 #include "base/stl_util.h"
 #include "class_linker-inl.h"
 #include "dex_file-inl.h"
+#include "fault_handler.h"
 #include "gc_root.h"
 #include "gc/accounting/card_table-inl.h"
 #include "indirect_reference_table-inl.h"
@@ -2144,7 +2145,7 @@
 
       VLOG(jni) << "[Registering JNI native method " << PrettyMethod(m) << "]";
 
-      m->RegisterNative(soa.Self(), fnPtr, is_fast);
+      m->RegisterNative(fnPtr, is_fast);
     }
     return JNI_OK;
   }
@@ -2160,14 +2161,14 @@
     for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
       mirror::ArtMethod* m = c->GetDirectMethod(i);
       if (m->IsNative()) {
-        m->UnregisterNative(soa.Self());
+        m->UnregisterNative();
         unregistered_count++;
       }
     }
     for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
       mirror::ArtMethod* m = c->GetVirtualMethod(i);
       if (m->IsNative()) {
-        m->UnregisterNative(soa.Self());
+        m->UnregisterNative();
         unregistered_count++;
       }
     }
@@ -2704,7 +2705,7 @@
     os << "JNIWeakGlobalRefType";
     return os;
   default:
-    LOG(FATAL) << "jobjectRefType[" << static_cast<int>(rhs) << "]";
-    return os;
+    LOG(::art::FATAL) << "jobjectRefType[" << static_cast<int>(rhs) << "]";
+    UNREACHABLE();
   }
 }
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index 231e9e5..c118471 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -15,11 +15,12 @@
  */
 
 #include "mem_map.h"
-#include "thread-inl.h"
 
-#include <inttypes.h>
 #include <backtrace/BacktraceMap.h>
+#include <inttypes.h>
+
 #include <memory>
+#include <sstream>
 
 // See CreateStartPos below.
 #ifdef __BIONIC__
@@ -28,6 +29,7 @@
 
 #include "base/stringprintf.h"
 #include "ScopedFd.h"
+#include "thread-inl.h"
 #include "utils.h"
 
 #define USE_ASHMEM 1
@@ -70,7 +72,7 @@
   return os;
 }
 
-MemMap::Maps MemMap::maps_;
+MemMap::Maps* MemMap::maps_ = nullptr;
 
 #if USE_ART_LOW_4G_ALLOCATOR
 // Handling mem_map in 32b address range for 64b architectures that do not support MAP_32BIT.
@@ -457,11 +459,12 @@
   // Remove it from maps_.
   MutexLock mu(Thread::Current(), *Locks::mem_maps_lock_);
   bool found = false;
-  for (auto it = maps_.lower_bound(base_begin_), end = maps_.end();
+  DCHECK(maps_ != nullptr);
+  for (auto it = maps_->lower_bound(base_begin_), end = maps_->end();
        it != end && it->first == base_begin_; ++it) {
     if (it->second == this) {
       found = true;
-      maps_.erase(it);
+      maps_->erase(it);
       break;
     }
   }
@@ -483,7 +486,8 @@
 
     // Add it to maps_.
     MutexLock mu(Thread::Current(), *Locks::mem_maps_lock_);
-    maps_.insert(std::pair<void*, MemMap*>(base_begin_, this));
+    DCHECK(maps_ != nullptr);
+    maps_->insert(std::make_pair(base_begin_, this));
   }
 }
 
@@ -614,7 +618,7 @@
 
 bool MemMap::HasMemMap(MemMap* map) {
   void* base_begin = map->BaseBegin();
-  for (auto it = maps_.lower_bound(base_begin), end = maps_.end();
+  for (auto it = maps_->lower_bound(base_begin), end = maps_->end();
        it != end && it->first == base_begin; ++it) {
     if (it->second == map) {
       return true;
@@ -626,7 +630,8 @@
 MemMap* MemMap::GetLargestMemMapAt(void* address) {
   size_t largest_size = 0;
   MemMap* largest_map = nullptr;
-  for (auto it = maps_.lower_bound(address), end = maps_.end();
+  DCHECK(maps_ != nullptr);
+  for (auto it = maps_->lower_bound(address), end = maps_->end();
        it != end && it->first == address; ++it) {
     MemMap* map = it->second;
     CHECK(map != nullptr);
@@ -638,6 +643,20 @@
   return largest_map;
 }
 
+void MemMap::Init() {
+  MutexLock mu(Thread::Current(), *Locks::mem_maps_lock_);
+  if (maps_ == nullptr) {
+    // dex2oat calls MemMap::Init twice since its needed before the runtime is created.
+    maps_ = new Maps;
+  }
+}
+
+void MemMap::Shutdown() {
+  MutexLock mu(Thread::Current(), *Locks::mem_maps_lock_);
+  delete maps_;
+  maps_ = nullptr;
+}
+
 std::ostream& operator<<(std::ostream& os, const MemMap& mem_map) {
   os << StringPrintf("[MemMap: %p-%p prot=0x%x %s]",
                      mem_map.BaseBegin(), mem_map.BaseEnd(), mem_map.GetProtect(),
diff --git a/runtime/mem_map.h b/runtime/mem_map.h
index 314bf8d..df1222c 100644
--- a/runtime/mem_map.h
+++ b/runtime/mem_map.h
@@ -138,6 +138,9 @@
 
   typedef AllocationTrackingMultiMap<void*, MemMap*, kAllocatorTagMaps> Maps;
 
+  static void Init() LOCKS_EXCLUDED(Locks::mem_maps_lock_);
+  static void Shutdown() LOCKS_EXCLUDED(Locks::mem_maps_lock_);
+
  private:
   MemMap(const std::string& name, uint8_t* begin, size_t size, void* base_begin, size_t base_size,
          int prot, bool reuse) LOCKS_EXCLUDED(Locks::mem_maps_lock_);
@@ -167,7 +170,7 @@
 #endif
 
   // All the non-empty MemMaps. Use a multimap as we do a reserve-and-divide (eg ElfMap::Load()).
-  static Maps maps_ GUARDED_BY(Locks::mem_maps_lock_);
+  static Maps* maps_ GUARDED_BY(Locks::mem_maps_lock_);
 
   friend class MemMapTest;  // To allow access to base_begin_ and base_size_.
 };
diff --git a/runtime/mem_map_test.cc b/runtime/mem_map_test.cc
index a78f463..14a72b9 100644
--- a/runtime/mem_map_test.cc
+++ b/runtime/mem_map_test.cc
@@ -87,6 +87,10 @@
     delete m1;
   }
 
+  void CommonInit() {
+    MemMap::Init();
+  }
+
 #if defined(__LP64__) && !defined(__x86_64__)
   static uintptr_t GetLinearScanPos() {
     return MemMap::next_mem_pos_;
@@ -101,10 +105,10 @@
 #endif
 
 TEST_F(MemMapTest, Start) {
+  CommonInit();
   uintptr_t start = GetLinearScanPos();
   EXPECT_LE(64 * KB, start);
   EXPECT_LT(start, static_cast<uintptr_t>(ART_BASE_ADDRESS));
-
 #ifdef __BIONIC__
   // Test a couple of values. Make sure they are different.
   uintptr_t last = 0;
@@ -122,6 +126,7 @@
 #endif
 
 TEST_F(MemMapTest, MapAnonymousEmpty) {
+  CommonInit();
   std::string error_msg;
   std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousEmpty",
                                              nullptr,
@@ -143,6 +148,7 @@
 
 #ifdef __LP64__
 TEST_F(MemMapTest, MapAnonymousEmpty32bit) {
+  CommonInit();
   std::string error_msg;
   std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousEmpty",
                                              nullptr,
@@ -157,6 +163,7 @@
 #endif
 
 TEST_F(MemMapTest, MapAnonymousExactAddr) {
+  CommonInit();
   std::string error_msg;
   // Map at an address that should work, which should succeed.
   std::unique_ptr<MemMap> map0(MemMap::MapAnonymous("MapAnonymous0",
@@ -200,6 +207,7 @@
 #endif
 
 TEST_F(MemMapTest, MapAnonymousExactAddr32bitHighAddr) {
+  CommonInit();
   // This test may not work under valgrind.
   if (RUNNING_ON_VALGRIND == 0) {
     uintptr_t start_addr = ART_BASE_ADDRESS + 0x1000000;
@@ -217,6 +225,7 @@
 }
 
 TEST_F(MemMapTest, MapAnonymousOverflow) {
+  CommonInit();
   std::string error_msg;
   uintptr_t ptr = 0;
   ptr -= kPageSize;  // Now it's close to the top.
@@ -232,6 +241,7 @@
 
 #ifdef __LP64__
 TEST_F(MemMapTest, MapAnonymousLow4GBExpectedTooHigh) {
+  CommonInit();
   std::string error_msg;
   std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousLow4GBExpectedTooHigh",
                                              reinterpret_cast<uint8_t*>(UINT64_C(0x100000000)),
@@ -244,6 +254,7 @@
 }
 
 TEST_F(MemMapTest, MapAnonymousLow4GBRangeTooHigh) {
+  CommonInit();
   std::string error_msg;
   std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousLow4GBRangeTooHigh",
                                              reinterpret_cast<uint8_t*>(0xF0000000),
@@ -257,6 +268,7 @@
 #endif
 
 TEST_F(MemMapTest, CheckNoGaps) {
+  CommonInit();
   std::string error_msg;
   constexpr size_t kNumPages = 3;
   // Map a 3-page mem map.
diff --git a/runtime/memory_region.h b/runtime/memory_region.h
index 6459963..4eb6d47 100644
--- a/runtime/memory_region.h
+++ b/runtime/memory_region.h
@@ -21,6 +21,7 @@
 
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/value_object.h"
 #include "globals.h"
 
 namespace art {
@@ -28,9 +29,9 @@
 // Memory regions are useful for accessing memory with bounds check in
 // debug mode. They can be safely passed by value and do not assume ownership
 // of the region.
-class MemoryRegion {
+class MemoryRegion FINAL : public ValueObject {
  public:
-  MemoryRegion() : pointer_(NULL), size_(0) {}
+  MemoryRegion() : pointer_(nullptr), size_(0) {}
   MemoryRegion(void* pointer, uintptr_t size) : pointer_(pointer), size_(size) {}
 
   void* pointer() const { return pointer_; }
diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h
index 1a65d99..664a412 100644
--- a/runtime/mirror/art_method-inl.h
+++ b/runtime/mirror/art_method-inl.h
@@ -24,7 +24,6 @@
 #include "class_linker.h"
 #include "dex_cache.h"
 #include "dex_file.h"
-#include "entrypoints/entrypoint_utils.h"
 #include "method_helper.h"
 #include "object-inl.h"
 #include "object_array.h"
@@ -176,32 +175,6 @@
   }
 }
 
-inline void ArtMethod::AssertPcIsWithinQuickCode(uintptr_t pc) {
-  if (!kIsDebugBuild) {
-    return;
-  }
-  if (IsNative() || IsRuntimeMethod() || IsProxyMethod()) {
-    return;
-  }
-  if (pc == GetQuickInstrumentationExitPc()) {
-    return;
-  }
-  const void* code = GetEntryPointFromQuickCompiledCode();
-  if (code == GetQuickToInterpreterBridge() || code == GetQuickInstrumentationEntryPoint()) {
-    return;
-  }
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  if (code == class_linker->GetQuickResolutionTrampoline() ||
-      code == class_linker->GetQuickToInterpreterBridgeTrampoline()) {
-    return;
-  }
-  DCHECK(IsWithinQuickCode(pc))
-      << PrettyMethod(this)
-      << " pc=" << std::hex << pc
-      << " code=" << code
-      << " size=" << GetCodeSize();
-}
-
 inline uint32_t ArtMethod::GetQuickOatCodeOffset() {
   DCHECK(!Runtime::Current()->IsStarted());
   return PointerToLowMemUInt32(GetEntryPointFromQuickCompiledCode());
@@ -222,27 +195,6 @@
   SetEntryPointFromPortableCompiledCode(reinterpret_cast<void*>(code_offset));
 }
 
-inline const void* ArtMethod::GetQuickOatEntryPoint() {
-  if (IsPortableCompiled() || IsAbstract() || IsRuntimeMethod() || IsProxyMethod()) {
-    return nullptr;
-  }
-  Runtime* runtime = Runtime::Current();
-  const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(this);
-  // On failure, instead of nullptr we get the quick-generic-jni-trampoline for native method
-  // indicating the generic JNI, or the quick-to-interpreter-bridge (but not the trampoline)
-  // for non-native methods.
-  DCHECK(entry_point != runtime->GetClassLinker()->GetQuickToInterpreterBridgeTrampoline());
-  if (UNLIKELY(entry_point == GetQuickToInterpreterBridge()) ||
-      UNLIKELY(entry_point == runtime->GetClassLinker()->GetQuickGenericJniTrampoline())) {
-    return nullptr;
-  }
-  return entry_point;
-}
-
-inline const void* ArtMethod::GetQuickOatCodePointer() {
-  return EntryPointToCodePointer(GetQuickOatEntryPoint());
-}
-
 inline const uint8_t* ArtMethod::GetMappingTable() {
   const void* code_pointer = GetQuickOatCodePointer();
   if (code_pointer == nullptr) {
@@ -341,69 +293,17 @@
   return result;
 }
 
-inline uintptr_t ArtMethod::NativePcOffset(const uintptr_t pc) {
+inline uintptr_t ArtMethod::NativeQuickPcOffset(const uintptr_t pc) {
   const void* code = Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(this);
   return pc - reinterpret_cast<uintptr_t>(code);
 }
 
-inline uintptr_t ArtMethod::NativePcOffset(const uintptr_t pc, const void* quick_entry_point) {
-  DCHECK(quick_entry_point != GetQuickToInterpreterBridge());
-  DCHECK(quick_entry_point == Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(this));
-  return pc - reinterpret_cast<uintptr_t>(quick_entry_point);
-}
-
 template<VerifyObjectFlags kVerifyFlags>
 inline void ArtMethod::SetNativeMethod(const void* native_method) {
   SetFieldPtr<false, true, kVerifyFlags>(
       OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_jni_), native_method);
 }
 
-inline QuickMethodFrameInfo ArtMethod::GetQuickFrameInfo() {
-  if (UNLIKELY(IsPortableCompiled())) {
-    // Portable compiled dex bytecode or jni stub.
-    return QuickMethodFrameInfo(kStackAlignment, 0u, 0u);
-  }
-  Runtime* runtime = Runtime::Current();
-  // For Proxy method we exclude direct method (there is only one direct method - constructor).
-  // Direct method is cloned from original java.lang.reflect.Proxy class together with code
-  // and as a result it is executed as usual quick compiled method without any stubs.
-  // So the frame info should be returned as it is a quick method not a stub.
-  if (UNLIKELY(IsAbstract()) || UNLIKELY(IsProxyMethod() && !IsDirect())) {
-    return runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
-  }
-  if (UNLIKELY(IsRuntimeMethod())) {
-    return runtime->GetRuntimeMethodFrameInfo(this);
-  }
-
-  const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(this);
-  // On failure, instead of nullptr we get the quick-generic-jni-trampoline for native method
-  // indicating the generic JNI, or the quick-to-interpreter-bridge (but not the trampoline)
-  // for non-native methods. And we really shouldn't see a failure for non-native methods here.
-  DCHECK(entry_point != runtime->GetClassLinker()->GetQuickToInterpreterBridgeTrampoline());
-  CHECK(entry_point != GetQuickToInterpreterBridge());
-
-  if (UNLIKELY(entry_point == runtime->GetClassLinker()->GetQuickGenericJniTrampoline())) {
-    // Generic JNI frame.
-    DCHECK(IsNative());
-    StackHandleScope<1> hs(Thread::Current());
-    uint32_t handle_refs =
-        MethodHelper(hs.NewHandle(this)).GetNumberOfReferenceArgsWithoutReceiver() + 1;
-    size_t scope_size = HandleScope::SizeOf(handle_refs);
-    QuickMethodFrameInfo callee_info = runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
-
-    // Callee saves + handle scope + method ref + alignment
-    size_t frame_size = RoundUp(callee_info.FrameSizeInBytes() + scope_size
-                                - sizeof(void*)  // callee-save frame stores a whole method pointer
-                                + sizeof(StackReference<mirror::ArtMethod>),
-                                kStackAlignment);
-
-    return QuickMethodFrameInfo(frame_size, callee_info.CoreSpillMask(), callee_info.FpSpillMask());
-  }
-
-  const void* code_pointer = EntryPointToCodePointer(entry_point);
-  return GetQuickFrameInfo(code_pointer);
-}
-
 inline QuickMethodFrameInfo ArtMethod::GetQuickFrameInfo(const void* code_pointer) {
   DCHECK(code_pointer != nullptr);
   DCHECK_EQ(code_pointer, GetQuickOatCodePointer());
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index 787c767..9584d15 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -23,6 +23,8 @@
 #include "class-inl.h"
 #include "dex_file-inl.h"
 #include "dex_instruction.h"
+#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
 #include "gc/accounting/card_table-inl.h"
 #include "interpreter/interpreter.h"
 #include "jni_internal.h"
@@ -203,7 +205,7 @@
   return DexFile::kDexNoIndex;
 }
 
-uintptr_t ArtMethod::ToNativePc(const uint32_t dex_pc) {
+uintptr_t ArtMethod::ToNativeQuickPc(const uint32_t dex_pc) {
   const void* entry_point = GetQuickOatEntryPoint();
   MappingTable table(
       entry_point != nullptr ? GetMappingTable(EntryPointToCodePointer(entry_point)) : nullptr);
@@ -281,19 +283,74 @@
   return found_dex_pc;
 }
 
+void ArtMethod::AssertPcIsWithinQuickCode(uintptr_t pc) {
+  if (IsNative() || IsRuntimeMethod() || IsProxyMethod()) {
+    return;
+  }
+  if (pc == reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc())) {
+    return;
+  }
+  const void* code = GetEntryPointFromQuickCompiledCode();
+  if (code == GetQuickInstrumentationEntryPoint()) {
+    return;
+  }
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  if (class_linker->IsQuickToInterpreterBridge(code) ||
+      class_linker->IsQuickResolutionStub(code)) {
+    return;
+  }
+  /*
+   * During a stack walk, a return PC may point past-the-end of the code
+   * in the case that the last instruction is a call that isn't expected to
+   * return.  Thus, we check <= code + GetCodeSize().
+   *
+   * NOTE: For Thumb both pc and code are offset by 1 indicating the Thumb state.
+   */
+  CHECK(PcIsWithinQuickCode(pc))
+      << PrettyMethod(this)
+      << " pc=" << std::hex << pc
+      << " code=" << code
+      << " size=" << GetCodeSize();
+}
+
 bool ArtMethod::IsEntrypointInterpreter() {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  const void* oat_quick_code = class_linker->GetOatMethodQuickCodeFor(this);
-  const void* oat_portable_code = class_linker->GetOatMethodPortableCodeFor(this);
   if (!IsPortableCompiled()) {  // Quick.
+    const void* oat_quick_code = class_linker->GetOatMethodQuickCodeFor(this);
     return oat_quick_code == nullptr ||
         oat_quick_code != GetEntryPointFromQuickCompiledCode();
   } else {  // Portable.
+    const void* oat_portable_code = class_linker->GetOatMethodPortableCodeFor(this);
     return oat_portable_code == nullptr ||
         oat_portable_code != GetEntryPointFromPortableCompiledCode();
   }
 }
 
+const void* ArtMethod::GetQuickOatEntryPoint() {
+  if (IsPortableCompiled() || IsAbstract() || IsRuntimeMethod() || IsProxyMethod()) {
+    return nullptr;
+  }
+  Runtime* runtime = Runtime::Current();
+  ClassLinker* class_linker = runtime->GetClassLinker();
+  const void* code = runtime->GetInstrumentation()->GetQuickCodeFor(this);
+  // On failure, instead of nullptr we get the quick-generic-jni-trampoline for native method
+  // indicating the generic JNI, or the quick-to-interpreter-bridge (but not the trampoline)
+  // for non-native methods.
+  if (class_linker->IsQuickToInterpreterBridge(code) ||
+      class_linker->IsQuickGenericJniStub(code)) {
+    return nullptr;
+  }
+  return code;
+}
+
+#ifndef NDEBUG
+uintptr_t ArtMethod::NativeQuickPcOffset(const uintptr_t pc, const void* quick_entry_point) {
+  CHECK_NE(quick_entry_point, GetQuickToInterpreterBridge());
+  CHECK_EQ(quick_entry_point, Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(this));
+  return pc - reinterpret_cast<uintptr_t>(quick_entry_point);
+}
+#endif
+
 void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result,
                        const char* shorty) {
   if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEnd())) {
@@ -357,7 +414,7 @@
         // stack. Continue execution in the interpreter.
         self->ClearException();
         ShadowFrame* shadow_frame = self->GetAndClearDeoptimizationShadowFrame(result);
-        self->SetTopOfStack(nullptr, 0);
+        self->SetTopOfStack(nullptr);
         self->SetTopOfShadowStack(shadow_frame);
         interpreter::EnterInterpreterFromDeoptimize(self, shadow_frame, result);
       }
@@ -379,8 +436,53 @@
   self->PopManagedStackFragment(fragment);
 }
 
-void ArtMethod::RegisterNative(Thread* self, const void* native_method, bool is_fast) {
-  DCHECK(Thread::Current() == self);
+QuickMethodFrameInfo ArtMethod::GetQuickFrameInfo() {
+  if (UNLIKELY(IsPortableCompiled())) {
+    // Portable compiled dex bytecode or jni stub.
+    return QuickMethodFrameInfo(kStackAlignment, 0u, 0u);
+  }
+  Runtime* runtime = Runtime::Current();
+  // For Proxy method we exclude direct method (there is only one direct method - constructor).
+  // Direct method is cloned from original java.lang.reflect.Proxy class together with code
+  // and as a result it is executed as usual quick compiled method without any stubs.
+  // So the frame info should be returned as it is a quick method not a stub.
+  if (UNLIKELY(IsAbstract()) || UNLIKELY(IsProxyMethod() && !IsDirect())) {
+    return runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
+  }
+  if (UNLIKELY(IsRuntimeMethod())) {
+    return runtime->GetRuntimeMethodFrameInfo(this);
+  }
+
+  const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(this);
+  ClassLinker* class_linker = runtime->GetClassLinker();
+  // On failure, instead of nullptr we get the quick-generic-jni-trampoline for native method
+  // indicating the generic JNI, or the quick-to-interpreter-bridge (but not the trampoline)
+  // for non-native methods. And we really shouldn't see a failure for non-native methods here.
+  DCHECK(!class_linker->IsQuickToInterpreterBridge(entry_point));
+
+  if (class_linker->IsQuickGenericJniStub(entry_point)) {
+    // Generic JNI frame.
+    DCHECK(IsNative());
+    StackHandleScope<1> hs(Thread::Current());
+    uint32_t handle_refs =
+        MethodHelper(hs.NewHandle(this)).GetNumberOfReferenceArgsWithoutReceiver() + 1;
+    size_t scope_size = HandleScope::SizeOf(handle_refs);
+    QuickMethodFrameInfo callee_info = runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
+
+    // Callee saves + handle scope + method ref + alignment
+    size_t frame_size = RoundUp(callee_info.FrameSizeInBytes() + scope_size
+                                - sizeof(void*)  // callee-save frame stores a whole method pointer
+                                + sizeof(StackReference<mirror::ArtMethod>),
+                                kStackAlignment);
+
+    return QuickMethodFrameInfo(frame_size, callee_info.CoreSpillMask(), callee_info.FpSpillMask());
+  }
+
+  const void* code_pointer = EntryPointToCodePointer(entry_point);
+  return GetQuickFrameInfo(code_pointer);
+}
+
+void ArtMethod::RegisterNative(const void* native_method, bool is_fast) {
   CHECK(IsNative()) << PrettyMethod(this);
   CHECK(!IsFastNative()) << PrettyMethod(this);
   CHECK(native_method != NULL) << PrettyMethod(this);
@@ -390,10 +492,10 @@
   SetNativeMethod(native_method);
 }
 
-void ArtMethod::UnregisterNative(Thread* self) {
+void ArtMethod::UnregisterNative() {
   CHECK(IsNative() && !IsFastNative()) << PrettyMethod(this);
   // restore stub to lookup native pointer via dlsym
-  RegisterNative(self, GetJniDlsymLookupStub(), false);
+  RegisterNative(GetJniDlsymLookupStub(), false);
 }
 
 }  // namespace mirror
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index 939d856..3b92012 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -39,7 +39,7 @@
 
 namespace mirror {
 
-typedef void (EntryPointFromInterpreter)(Thread* self, MethodHelper& mh,
+typedef void (EntryPointFromInterpreter)(Thread* self, MethodHelper* mh,
     const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, JValue* result);
 
 // C++ mirror of java.lang.reflect.ArtMethod.
@@ -302,7 +302,10 @@
 
   uint32_t GetCodeSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool IsWithinQuickCode(uintptr_t pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  // Check whether the given PC is within the quick compiled code associated with this method's
+  // quick entrypoint. This code isn't robust for instrumentation, etc. and is only used for
+  // debug purposes.
+  bool PcIsWithinQuickCode(uintptr_t pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     uintptr_t code = reinterpret_cast<uintptr_t>(GetEntryPointFromQuickCompiledCode());
     if (code == 0) {
       return pc == 0;
@@ -329,16 +332,21 @@
   void SetQuickOatCodeOffset(uint32_t code_offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void SetPortableOatCodeOffset(uint32_t code_offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static const void* EntryPointToCodePointer(const void* entry_point) ALWAYS_INLINE {
+  ALWAYS_INLINE static const void* EntryPointToCodePointer(const void* entry_point) {
     uintptr_t code = reinterpret_cast<uintptr_t>(entry_point);
-    code &= ~0x1;  // TODO: Make this Thumb2 specific.
+    // TODO: Make this Thumb2 specific. It is benign on other architectures as code is always at
+    //       least 2 byte aligned.
+    code &= ~0x1;
     return reinterpret_cast<const void*>(code);
   }
 
-  // Actual entry point pointer to compiled oat code or nullptr.
+  // Actual entry point pointer to compiled oat code or nullptr if method has no compiled code.
   const void* GetQuickOatEntryPoint() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Actual pointer to compiled oat code or nullptr.
-  const void* GetQuickOatCodePointer() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const void* GetQuickOatCodePointer() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return EntryPointToCodePointer(GetQuickOatEntryPoint());
+  }
 
   // Callers should wrap the uint8_t* in a MappingTable instance for convenient access.
   const uint8_t* GetMappingTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -378,24 +386,25 @@
   QuickMethodFrameInfo GetQuickFrameInfo(const void* code_pointer)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  size_t GetReturnPcOffsetInBytes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return GetReturnPcOffsetInBytes(GetFrameSizeInBytes());
+  FrameOffset GetReturnPcOffset() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return GetReturnPcOffset(GetFrameSizeInBytes());
   }
 
-  size_t GetReturnPcOffsetInBytes(uint32_t frame_size_in_bytes)
+  FrameOffset GetReturnPcOffset(uint32_t frame_size_in_bytes)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK_EQ(frame_size_in_bytes, GetFrameSizeInBytes());
-    return frame_size_in_bytes - sizeof(void*);
+    return FrameOffset(frame_size_in_bytes - sizeof(void*));
   }
 
-  size_t GetHandleScopeOffsetInBytes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return sizeof(void*);
+  FrameOffset GetHandleScopeOffset() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    DCHECK_LT(sizeof(void*), GetFrameSizeInBytes());
+    return FrameOffset(sizeof(void*));
   }
 
-  void RegisterNative(Thread* self, const void* native_method, bool is_fast)
+  void RegisterNative(const void* native_method, bool is_fast)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void UnregisterNative(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void UnregisterNative() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static MemberOffset NativeMethodOffset() {
     return OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_jni_);
@@ -423,16 +432,23 @@
 
   bool IsImtConflictMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  uintptr_t NativePcOffset(const uintptr_t pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  uintptr_t NativePcOffset(const uintptr_t pc, const void* quick_entry_point)
+  uintptr_t NativeQuickPcOffset(const uintptr_t pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+#ifdef NDEBUG
+  uintptr_t NativeQuickPcOffset(const uintptr_t pc, const void* quick_entry_point)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return pc - reinterpret_cast<uintptr_t>(quick_entry_point);
+  }
+#else
+  uintptr_t NativeQuickPcOffset(const uintptr_t pc, const void* quick_entry_point)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+#endif
 
   // Converts a native PC to a dex PC.
   uint32_t ToDexPc(const uintptr_t pc, bool abort_on_failure = true)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Converts a dex PC to a native PC.
-  uintptr_t ToNativePc(const uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  uintptr_t ToNativeQuickPc(const uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Find the catch block for the given exception type and dex_pc. When a catch block is found,
   // indicates whether the found catch block is responsible for clearing the exception or whether
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 3d3ae16..e3295ef 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -112,7 +112,8 @@
 
 template<VerifyObjectFlags kVerifyFlags>
 inline ArtMethod* Class::GetVirtualMethod(uint32_t i) {
-  DCHECK(IsResolved<kVerifyFlags>() || IsErroneous<kVerifyFlags>());
+  DCHECK(IsResolved<kVerifyFlags>() || IsErroneous<kVerifyFlags>())
+      << PrettyClass(this) << " status=" << GetStatus();
   return GetVirtualMethods()->Get(i);
 }
 
@@ -615,12 +616,11 @@
 
 template <bool kVisitClass, typename Visitor>
 inline void Class::VisitReferences(mirror::Class* klass, const Visitor& visitor) {
-  // Visit the static fields first so that we don't overwrite the SFields / IFields instance
-  // fields.
   VisitInstanceFieldsReferences<kVisitClass>(klass, visitor);
-  if (!IsTemp()) {
+  if (!IsTemp() && IsResolved()) {
     // Temp classes don't ever populate imt/vtable or static fields and they are not even
-    // allocated with the right size for those.
+    // allocated with the right size for those. Also, unresolved classes don't have fields
+    // linked yet.
     VisitStaticFieldsReferences<kVisitClass>(this, visitor);
     if (ShouldHaveEmbeddedImtAndVTable()) {
       VisitEmbeddedImtAndVTable(visitor);
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 2d49121..c06071b 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -27,6 +27,7 @@
 #include "object_callbacks.h"
 #include "primitive.h"
 #include "read_barrier_option.h"
+#include "utils.h"
 
 namespace art {
 
@@ -507,7 +508,7 @@
   // The size of java.lang.Class.class.
   static uint32_t ClassClassSize() {
     // The number of vtable entries in java.lang.Class.
-    uint32_t vtable_entries = Object::kVTableLength + 64;
+    uint32_t vtable_entries = Object::kVTableLength + 66;
     return ComputeClassSize(true, vtable_entries, 0, 0, 0, 1, 0);
   }
 
@@ -840,7 +841,7 @@
 
   // Returns the number of static fields containing reference types.
   uint32_t NumReferenceStaticFields() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK(IsResolved() || IsErroneous());
+    DCHECK(IsResolved() || IsErroneous()) << PrettyClass(this) << " status=" << GetStatus();
     return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_));
   }
 
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 1bbcf8e..b2b2420 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -478,6 +478,7 @@
   friend struct art::ObjectOffsets;  // for verifying offset information
   friend class CopyObjectVisitor;  // for CopyObject().
   friend class CopyClassVisitor;   // for CopyObject().
+  DISALLOW_ALLOCATION();
   DISALLOW_IMPLICIT_CONSTRUCTORS(Object);
 };
 
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index a2a0626..a0aaa9e 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -80,26 +80,6 @@
   EXPECT_EQ(kObjectHeaderSize, sizeof(Object));
 }
 
-// Keep the assembly code constats in sync.
-TEST_F(ObjectTest, AsmConstants) {
-  EXPECT_EQ(CLASS_OFFSET, Object::ClassOffset().Int32Value());
-  EXPECT_EQ(LOCK_WORD_OFFSET, Object::MonitorOffset().Int32Value());
-
-  EXPECT_EQ(CLASS_COMPONENT_TYPE_OFFSET, Class::ComponentTypeOffset().Int32Value());
-
-  EXPECT_EQ(ARRAY_LENGTH_OFFSET, Array::LengthOffset().Int32Value());
-  EXPECT_EQ(OBJECT_ARRAY_DATA_OFFSET, Array::DataOffset(sizeof(HeapReference<Object>)).Int32Value());
-
-  EXPECT_EQ(STRING_VALUE_OFFSET, String::ValueOffset().Int32Value());
-  EXPECT_EQ(STRING_COUNT_OFFSET, String::CountOffset().Int32Value());
-  EXPECT_EQ(STRING_OFFSET_OFFSET, String::OffsetOffset().Int32Value());
-  EXPECT_EQ(STRING_DATA_OFFSET, Array::DataOffset(sizeof(uint16_t)).Int32Value());
-
-  EXPECT_EQ(METHOD_DEX_CACHE_METHODS_OFFSET, ArtMethod::DexCacheResolvedMethodsOffset().Int32Value());
-  EXPECT_EQ(METHOD_PORTABLE_CODE_OFFSET, ArtMethod::EntryPointFromPortableCompiledCodeOffset().Int32Value());
-  EXPECT_EQ(METHOD_QUICK_CODE_OFFSET, ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value());
-}
-
 TEST_F(ObjectTest, IsInSamePackage) {
   // Matches
   EXPECT_TRUE(Class::IsInSamePackage("Ljava/lang/Object;", "Ljava/lang/Class;"));
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index 1320ab7..64408a6 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -17,8 +17,6 @@
 #ifndef ART_RUNTIME_MIRROR_STRING_H_
 #define ART_RUNTIME_MIRROR_STRING_H_
 
-#include <gtest/gtest.h>
-
 #include "gc_root.h"
 #include "object.h"
 #include "object_callbacks.h"
@@ -163,7 +161,8 @@
   static GcRoot<Class> java_lang_String_;
 
   friend struct art::StringOffsets;  // for verifying offset information
-  FRIEND_TEST(ObjectTest, StringLength);  // for SetOffset and SetCount
+  ART_FRIEND_TEST(ObjectTest, StringLength);  // for SetOffset and SetCount
+
   DISALLOW_IMPLICIT_CONSTRUCTORS(String);
 };
 
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 65a7919..11e9efc 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -192,12 +192,13 @@
       mirror::Class* result = class_linker->DefineClass(soa.Self(), descriptor.c_str(),
                                                         class_loader, *dex_file, *dex_class_def);
       if (result != nullptr) {
-        VLOG(class_linker) << "DexFile_defineClassNative returning " << result;
+        VLOG(class_linker) << "DexFile_defineClassNative returning " << result
+                           << " for " << class_name.c_str();
         return soa.AddLocalReference<jclass>(result);
       }
     }
   }
-  VLOG(class_linker) << "Failed to find dex_class_def";
+  VLOG(class_linker) << "Failed to find dex_class_def " << class_name.c_str();
   return nullptr;
 }
 
diff --git a/runtime/native/java_lang_Runtime.cc b/runtime/native/java_lang_Runtime.cc
index 62ca14d..f9a1cee 100644
--- a/runtime/native/java_lang_Runtime.cc
+++ b/runtime/native/java_lang_Runtime.cc
@@ -37,8 +37,7 @@
   Runtime::Current()->GetHeap()->CollectGarbage(false);
 }
 
-static void Runtime_nativeExit(JNIEnv*, jclass, jint status) NO_RETURN;
-static void Runtime_nativeExit(JNIEnv*, jclass, jint status) {
+[[noreturn]] static void Runtime_nativeExit(JNIEnv*, jclass, jint status) {
   LOG(INFO) << "System.exit called, status: " << status;
   Runtime::Current()->CallExitHook(status);
   exit(status);
diff --git a/runtime/native/scoped_fast_native_object_access.h b/runtime/native/scoped_fast_native_object_access.h
index 606d62d..dfabff5 100644
--- a/runtime/native/scoped_fast_native_object_access.h
+++ b/runtime/native/scoped_fast_native_object_access.h
@@ -17,7 +17,7 @@
 #ifndef ART_RUNTIME_NATIVE_SCOPED_FAST_NATIVE_OBJECT_ACCESS_H_
 #define ART_RUNTIME_NATIVE_SCOPED_FAST_NATIVE_OBJECT_ACCESS_H_
 
-#include "mirror/art_method.h"
+#include "mirror/art_method-inl.h"
 #include "scoped_thread_state_change.h"
 
 namespace art {
diff --git a/runtime/native_bridge_art_interface.cc b/runtime/native_bridge_art_interface.cc
index bc191b4..b0d8e87 100644
--- a/runtime/native_bridge_art_interface.cc
+++ b/runtime/native_bridge_art_interface.cc
@@ -107,10 +107,11 @@
   GetMethodShorty, GetNativeMethodCount, GetNativeMethods
 };
 
-void LoadNativeBridge(std::string& native_bridge_library_filename) {
-  android::LoadNativeBridge(native_bridge_library_filename.c_str(), &native_bridge_art_callbacks_);
+bool LoadNativeBridge(std::string& native_bridge_library_filename) {
   VLOG(startup) << "Runtime::Setup native bridge library: "
       << (native_bridge_library_filename.empty() ? "(empty)" : native_bridge_library_filename);
+  return android::LoadNativeBridge(native_bridge_library_filename.c_str(),
+                                   &native_bridge_art_callbacks_);
 }
 
 void PreInitializeNativeBridge(std::string dir) {
diff --git a/runtime/native_bridge_art_interface.h b/runtime/native_bridge_art_interface.h
index 026cd82..090cddb 100644
--- a/runtime/native_bridge_art_interface.h
+++ b/runtime/native_bridge_art_interface.h
@@ -26,7 +26,7 @@
 // Mirror libnativebridge interface. Done to have the ART callbacks out of line, and not require
 // the system/core header file in other files.
 
-void LoadNativeBridge(std::string& native_bridge_library_filename);
+bool LoadNativeBridge(std::string& native_bridge_library_filename);
 
 // This is mostly for testing purposes, as in a full system this is called by Zygote code.
 void PreInitializeNativeBridge(std::string dir);
diff --git a/runtime/oat.cc b/runtime/oat.cc
index 6810d73..0d7fb01 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -23,7 +23,7 @@
 namespace art {
 
 const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
-const uint8_t OatHeader::kOatVersion[] = { '0', '4', '2', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '4', '3', '\0' };
 
 static size_t ComputeOatHeaderSize(const SafeMap<std::string, std::string>* variable_data) {
   size_t estimate = 0U;
@@ -39,7 +39,7 @@
 }
 
 OatHeader* OatHeader::Create(InstructionSet instruction_set,
-                             const InstructionSetFeatures& instruction_set_features,
+                             const InstructionSetFeatures* instruction_set_features,
                              const std::vector<const DexFile*>* dex_files,
                              uint32_t image_file_location_oat_checksum,
                              uint32_t image_file_location_oat_data_begin,
@@ -60,7 +60,7 @@
 }
 
 OatHeader::OatHeader(InstructionSet instruction_set,
-                     const InstructionSetFeatures& instruction_set_features,
+                     const InstructionSetFeatures* instruction_set_features,
                      const std::vector<const DexFile*>* dex_files,
                      uint32_t image_file_location_oat_checksum,
                      uint32_t image_file_location_oat_data_begin,
@@ -76,8 +76,8 @@
   instruction_set_ = instruction_set;
   UpdateChecksum(&instruction_set_, sizeof(instruction_set_));
 
-  instruction_set_features_ = instruction_set_features;
-  UpdateChecksum(&instruction_set_features_, sizeof(instruction_set_features_));
+  instruction_set_features_bitmap_ = instruction_set_features->AsBitmap();
+  UpdateChecksum(&instruction_set_features_bitmap_, sizeof(instruction_set_features_bitmap_));
 
   dex_file_count_ = dex_files->size();
   UpdateChecksum(&dex_file_count_, sizeof(dex_file_count_));
@@ -149,9 +149,9 @@
   return instruction_set_;
 }
 
-const InstructionSetFeatures& OatHeader::GetInstructionSetFeatures() const {
+uint32_t OatHeader::GetInstructionSetFeaturesBitmap() const {
   CHECK(IsValid());
-  return instruction_set_features_;
+  return instruction_set_features_bitmap_;
 }
 
 uint32_t OatHeader::GetExecutableOffset() const {
diff --git a/runtime/oat.h b/runtime/oat.h
index 6a32e3e..92b98b1 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -37,7 +37,7 @@
   static constexpr const char* kDex2OatHostKey = "dex2oat-host";
 
   static OatHeader* Create(InstructionSet instruction_set,
-                           const InstructionSetFeatures& instruction_set_features,
+                           const InstructionSetFeatures* instruction_set_features,
                            const std::vector<const DexFile*>* dex_files,
                            uint32_t image_file_location_oat_checksum,
                            uint32_t image_file_location_oat_data_begin,
@@ -93,7 +93,7 @@
   void SetImagePatchDelta(int32_t off);
 
   InstructionSet GetInstructionSet() const;
-  const InstructionSetFeatures& GetInstructionSetFeatures() const;
+  uint32_t GetInstructionSetFeaturesBitmap() const;
   uint32_t GetImageFileLocationOatChecksum() const;
   uint32_t GetImageFileLocationOatDataBegin() const;
 
@@ -106,7 +106,7 @@
 
  private:
   OatHeader(InstructionSet instruction_set,
-            const InstructionSetFeatures& instruction_set_features,
+            const InstructionSetFeatures* instruction_set_features,
             const std::vector<const DexFile*>* dex_files,
             uint32_t image_file_location_oat_checksum,
             uint32_t image_file_location_oat_data_begin,
@@ -119,7 +119,7 @@
   uint32_t adler32_checksum_;
 
   InstructionSet instruction_set_;
-  InstructionSetFeatures instruction_set_features_;
+  uint32_t instruction_set_features_bitmap_;
   uint32_t dex_file_count_;
   uint32_t executable_offset_;
   uint32_t interpreter_to_interpreter_bridge_offset_;
diff --git a/runtime/offsets.cc b/runtime/offsets.cc
index 3691401..f59ed88 100644
--- a/runtime/offsets.cc
+++ b/runtime/offsets.cc
@@ -16,7 +16,7 @@
 
 #include "offsets.h"
 
-#include <iostream>  // NOLINT
+#include <ostream>
 
 namespace art {
 
diff --git a/runtime/offsets.h b/runtime/offsets.h
index 72a6b0f..9d5063f 100644
--- a/runtime/offsets.h
+++ b/runtime/offsets.h
@@ -17,7 +17,8 @@
 #ifndef ART_RUNTIME_OFFSETS_H_
 #define ART_RUNTIME_OFFSETS_H_
 
-#include <iostream>  // NOLINT
+#include <ostream>
+
 #include "globals.h"
 
 namespace art {
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index d820026..6b64c25 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -16,6 +16,8 @@
 
 #include "parsed_options.h"
 
+#include <sstream>
+
 #ifdef HAVE_ANDROID_OS
 #include "cutils/properties.h"
 #endif
@@ -205,7 +207,7 @@
 
 bool ParsedOptions::ParseXGcOption(const std::string& option) {
   std::vector<std::string> gc_options;
-  Split(option.substr(strlen("-Xgc:")), ',', gc_options);
+  Split(option.substr(strlen("-Xgc:")), ',', &gc_options);
   for (const std::string& gc_option : gc_options) {
     gc::CollectorType collector_type = ParseCollectorType(gc_option);
     if (collector_type != gc::kCollectorTypeNone) {
@@ -501,7 +503,7 @@
       is_explicit_gc_disabled_ = true;
     } else if (StartsWith(option, "-verbose:")) {
       std::vector<std::string> verbose_options;
-      Split(option.substr(strlen("-verbose:")), ',', verbose_options);
+      Split(option.substr(strlen("-verbose:")), ',', &verbose_options);
       for (size_t i = 0; i < verbose_options.size(); ++i) {
         if (verbose_options[i] == "class") {
           gLogVerbosity.class_linker = true;
@@ -534,9 +536,6 @@
           return false;
         }
       }
-    } else if (StartsWith(option, "-verbose-methods:")) {
-      gLogVerbosity.compiler = false;
-      Split(option.substr(strlen("-verbose-methods:")), ',', gVerboseMethods);
     } else if (StartsWith(option, "-Xlockprofthreshold:")) {
       if (!ParseUnsignedInteger(option, ':', &lock_profiling_threshold_)) {
         return false;
diff --git a/runtime/profiler.cc b/runtime/profiler.cc
index cde4177..e399195 100644
--- a/runtime/profiler.cc
+++ b/runtime/profiler.cc
@@ -16,9 +16,11 @@
 
 #include "profiler.h"
 
-#include <fstream>
-#include <sys/uio.h>
 #include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+
+#include <fstream>
 
 #include "base/stl_util.h"
 #include "base/unix_file/fd_file.h"
@@ -95,7 +97,7 @@
   switch (profile_options.GetProfileType()) {
     case kProfilerMethod: {
       mirror::ArtMethod* method = thread->GetCurrentMethod(nullptr);
-      if (false && method == nullptr) {
+      if ((false) && method == nullptr) {
         LOG(INFO) << "No current method available";
         std::ostringstream os;
         thread->Dump(os);
@@ -742,7 +744,7 @@
     return;
   }
   std::vector<std::string> summary_info;
-  Split(line, '/', summary_info);
+  Split(line, '/', &summary_info);
   if (summary_info.size() != 3) {
     // Bad summary info.  It should be count/nullcount/bootcount
     return;
@@ -757,7 +759,7 @@
       break;
     }
     std::vector<std::string> info;
-    Split(line, '/', info);
+    Split(line, '/', &info);
     if (info.size() != 3 && info.size() != 4) {
       // Malformed.
       break;
@@ -770,10 +772,10 @@
       context_map = new PreviousContextMap();
       std::string context_counts_str = info[3].substr(1, info[3].size() - 2);
       std::vector<std::string> context_count_pairs;
-      Split(context_counts_str, '#', context_count_pairs);
+      Split(context_counts_str, '#', &context_count_pairs);
       for (uint32_t i = 0; i < context_count_pairs.size(); ++i) {
         std::vector<std::string> context_count;
-        Split(context_count_pairs[i], ':', context_count);
+        Split(context_count_pairs[i], ':', &context_count);
         if (context_count.size() == 2) {
           // Handles the situtation when the profile file doesn't contain context information.
           uint32_t dexpc = strtoul(context_count[0].c_str(), nullptr, 10);
@@ -819,7 +821,7 @@
     return false;
   }
   std::vector<std::string> summary_info;
-  Split(line, '/', summary_info);
+  Split(line, '/', &summary_info);
   if (summary_info.size() != 3) {
     // Bad summary info.  It should be total/null/boot.
     return false;
@@ -837,7 +839,7 @@
       break;
     }
     std::vector<std::string> info;
-    Split(line, '/', info);
+    Split(line, '/', &info);
     if (info.size() != 3 && info.size() != 4) {
       // Malformed.
       return false;
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index 2c158ba..c58735a 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -19,6 +19,7 @@
 #include "arch/context.h"
 #include "dex_instruction.h"
 #include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
 #include "handle_scope-inl.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
@@ -96,7 +97,7 @@
       if (found_dex_pc != DexFile::kDexNoIndex) {
         exception_handler_->SetHandlerMethod(method.Get());
         exception_handler_->SetHandlerDexPc(found_dex_pc);
-        exception_handler_->SetHandlerQuickFramePc(method->ToNativePc(found_dex_pc));
+        exception_handler_->SetHandlerQuickFramePc(method->ToNativeQuickPc(found_dex_pc));
         exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame());
         return false;  // End stack walk.
       }
@@ -299,7 +300,7 @@
   InstrumentationStackVisitor(Thread* self, bool is_deoptimization, size_t frame_depth)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       : StackVisitor(self, nullptr),
-        self_(self), frame_depth_(frame_depth),
+        frame_depth_(frame_depth),
         instrumentation_frames_to_pop_(0) {
     CHECK_NE(frame_depth_, kInvalidFrameDepth);
   }
@@ -308,7 +309,7 @@
     size_t current_frame_depth = GetFrameDepth();
     if (current_frame_depth < frame_depth_) {
       CHECK(GetMethod() != nullptr);
-      if (UNLIKELY(GetQuickInstrumentationExitPc() == GetReturnPc())) {
+      if (UNLIKELY(reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc()) == GetReturnPc())) {
         ++instrumentation_frames_to_pop_;
       }
       return true;
@@ -323,7 +324,6 @@
   }
 
  private:
-  Thread* const self_;
   const size_t frame_depth_;
   size_t instrumentation_frames_to_pop_;
 
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 23f8076..b57e48f 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -19,6 +19,7 @@
 #include "class_linker.h"
 #include "common_throws.h"
 #include "dex_file-inl.h"
+#include "entrypoints/entrypoint_utils.h"
 #include "jni_internal.h"
 #include "method_helper-inl.h"
 #include "mirror/art_field-inl.h"
@@ -528,7 +529,7 @@
 }
 
 void InvokeWithShadowFrame(Thread* self, ShadowFrame* shadow_frame, uint16_t arg_offset,
-                           MethodHelper& mh, JValue* result) {
+                           MethodHelper* mh, JValue* result) {
   // We want to make sure that the stack is not within a small distance from the
   // protected region in case we are calling into a leaf function whose stack
   // check has been elided.
@@ -537,10 +538,10 @@
     return;
   }
 
-  ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
+  ArgArray arg_array(mh->GetShorty(), mh->GetShortyLength());
   arg_array.BuildArgArrayFromFrame(shadow_frame, arg_offset);
   shadow_frame->GetMethod()->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), result,
-                                    mh.GetShorty());
+                                    mh->GetShorty());
 }
 
 jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject javaMethod,
diff --git a/runtime/reflection.h b/runtime/reflection.h
index 23d8e05..f9a7951 100644
--- a/runtime/reflection.h
+++ b/runtime/reflection.h
@@ -65,7 +65,7 @@
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 void InvokeWithShadowFrame(Thread* self, ShadowFrame* shadow_frame, uint16_t arg_offset,
-                           MethodHelper& mh, JValue* result)
+                           MethodHelper* mh, JValue* result)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject method, jobject receiver,
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 42d05a9..8ba098f 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -43,10 +43,14 @@
 #include "arch/x86/registers_x86.h"
 #include "arch/x86_64/quick_method_frame_info_x86_64.h"
 #include "arch/x86_64/registers_x86_64.h"
+#include "asm_support.h"
 #include "atomic.h"
+#include "base/dumpable.h"
+#include "base/unix_file/fd_file.h"
 #include "class_linker.h"
 #include "debugger.h"
 #include "elf_file.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
 #include "fault_handler.h"
 #include "gc/accounting/card_table-inl.h"
 #include "gc/heap.h"
@@ -92,10 +96,9 @@
 
 namespace art {
 
+// If a signal isn't handled properly, enable a handler that attempts to dump the Java stack.
 static constexpr bool kEnableJavaStackTraceHandler = false;
-const char* Runtime::kDefaultInstructionSetFeatures =
-    STRINGIFY(ART_DEFAULT_INSTRUCTION_SET_FEATURES);
-Runtime* Runtime::instance_ = NULL;
+Runtime* Runtime::instance_ = nullptr;
 
 Runtime::Runtime()
     : instruction_set_(kNone),
@@ -144,10 +147,15 @@
       target_sdk_version_(0),
       implicit_null_checks_(false),
       implicit_so_checks_(false),
-      implicit_suspend_checks_(false) {
+      implicit_suspend_checks_(false),
+      is_native_bridge_loaded_(false) {
+  CheckAsmSupportOffsetsAndSizes();
 }
 
 Runtime::~Runtime() {
+  if (is_native_bridge_loaded_) {
+    UnloadNativeBridge();
+  }
   if (dump_gc_performance_on_shutdown_) {
     // This can't be called from the Heap destructor below because it
     // could call RosAlloc::InspectAll() which needs the thread_list
@@ -169,9 +177,6 @@
     BackgroundMethodSamplingProfiler::Shutdown();
   }
 
-  // Shutdown the fault manager if it was initialized.
-  fault_manager.Shutdown();
-
   Trace::Shutdown();
 
   // Make sure to let the GC complete if it is running.
@@ -184,6 +189,10 @@
 
   // Make sure all other non-daemon threads have terminated, and all daemon threads are suspended.
   delete thread_list_;
+
+  // Shutdown the fault manager if it was initialized.
+  fault_manager.Shutdown();
+
   delete monitor_list_;
   delete monitor_pool_;
   delete class_linker_;
@@ -193,13 +202,14 @@
   Thread::Shutdown();
   QuasiAtomic::Shutdown();
   verifier::MethodVerifier::Shutdown();
+  MemMap::Shutdown();
   // TODO: acquire a static mutex on Runtime to avoid racing.
   CHECK(instance_ == nullptr || instance_ == this);
   instance_ = nullptr;
 }
 
 struct AbortState {
-  void Dump(std::ostream& os) {
+  void Dump(std::ostream& os) const {
     if (gAborting > 1) {
       os << "Runtime aborting --- recursively, so no thread-specific detail!\n";
       return;
@@ -230,7 +240,7 @@
   }
 
   // No thread-safety analysis as we do explicitly test for holding the mutator lock.
-  void DumpThread(std::ostream& os, Thread* self) NO_THREAD_SAFETY_ANALYSIS {
+  void DumpThread(std::ostream& os, Thread* self) const NO_THREAD_SAFETY_ANALYSIS {
     DCHECK(Locks::mutator_lock_->IsExclusiveHeld(self) || Locks::mutator_lock_->IsSharedHeld(self));
     self->Dump(os);
     if (self->IsExceptionPending()) {
@@ -242,7 +252,7 @@
     }
   }
 
-  void DumpAllThreads(std::ostream& os, Thread* self) {
+  void DumpAllThreads(std::ostream& os, Thread* self) const {
     Runtime* runtime = Runtime::Current();
     if (runtime != nullptr) {
       ThreadList* thread_list = runtime->GetThreadList();
@@ -425,12 +435,11 @@
       return false;
     }
   } else {
-    bool have_native_bridge = !native_bridge_library_filename_.empty();
-    if (have_native_bridge) {
+    if (is_native_bridge_loaded_) {
       PreInitializeNativeBridge(".");
     }
-    DidForkFromZygote(self->GetJniEnv(), have_native_bridge ? NativeBridgeAction::kInitialize :
-        NativeBridgeAction::kUnload, GetInstructionSetString(kRuntimeISA));
+    DidForkFromZygote(self->GetJniEnv(), NativeBridgeAction::kInitialize,
+                      GetInstructionSetString(kRuntimeISA));
   }
 
   StartDaemonThreads();
@@ -509,14 +518,17 @@
 void Runtime::DidForkFromZygote(JNIEnv* env, NativeBridgeAction action, const char* isa) {
   is_zygote_ = false;
 
-  switch (action) {
-    case NativeBridgeAction::kUnload:
-      UnloadNativeBridge();
-      break;
+  if (is_native_bridge_loaded_) {
+    switch (action) {
+      case NativeBridgeAction::kUnload:
+        UnloadNativeBridge();
+        is_native_bridge_loaded_ = false;
+        break;
 
-    case NativeBridgeAction::kInitialize:
-      InitializeNativeBridge(env, isa);
-      break;
+      case NativeBridgeAction::kInitialize:
+        InitializeNativeBridge(env, isa);
+        break;
+    }
   }
 
   // Create the thread pool.
@@ -645,6 +657,8 @@
 bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized) {
   CHECK_EQ(sysconf(_SC_PAGE_SIZE), kPageSize);
 
+  MemMap::Init();
+
   std::unique_ptr<ParsedOptions> options(ParsedOptions::Create(raw_options, ignore_unrecognized));
   if (options.get() == nullptr) {
     LOG(ERROR) << "Failed to parse options";
@@ -800,7 +814,7 @@
     }
   } else if (!IsCompiler() || !image_dex2oat_enabled_) {
     std::vector<std::string> dex_filenames;
-    Split(boot_class_path_string_, ':', dex_filenames);
+    Split(boot_class_path_string_, ':', &dex_filenames);
     std::vector<const DexFile*> boot_class_path;
     OpenDexFiles(dex_filenames, options->image_, boot_class_path);
     class_linker_->InitWithoutImage(boot_class_path);
@@ -844,14 +858,14 @@
   // Pre-allocate an OutOfMemoryError for the double-OOME case.
   self->ThrowNewException(ThrowLocation(), "Ljava/lang/OutOfMemoryError;",
                           "OutOfMemoryError thrown while trying to throw OutOfMemoryError; "
-                          "no stack available");
+                          "no stack trace available");
   pre_allocated_OutOfMemoryError_ = GcRoot<mirror::Throwable>(self->GetException(NULL));
   self->ClearException();
 
   // Pre-allocate a NoClassDefFoundError for the common case of failing to find a system class
   // ahead of checking the application's class loader.
   self->ThrowNewException(ThrowLocation(), "Ljava/lang/NoClassDefFoundError;",
-                          "Class not found using the boot class loader; no stack available");
+                          "Class not found using the boot class loader; no stack trace available");
   pre_allocated_NoClassDefFoundError_ = GcRoot<mirror::Throwable>(self->GetException(NULL));
   self->ClearException();
 
@@ -882,8 +896,7 @@
   // Runtime::Start():
   //   DidForkFromZygote(kInitialize) -> try to initialize any native bridge given.
   //   No-op wrt native bridge.
-  native_bridge_library_filename_ = options->native_bridge_library_filename_;
-  LoadNativeBridge(native_bridge_library_filename_);
+  is_native_bridge_loaded_ = LoadNativeBridge(options->native_bridge_library_filename_);
 
   VLOG(startup) << "Runtime::Init exiting";
   return true;
@@ -911,7 +924,7 @@
   {
     std::string mapped_name(StringPrintf(OS_SHARED_LIB_FORMAT_STR, "javacore"));
     std::string reason;
-    if (!instance_->java_vm_->LoadNativeLibrary(env, mapped_name, nullptr, &reason)) {
+    if (!java_vm_->LoadNativeLibrary(env, mapped_name, nullptr, &reason)) {
       LOG(FATAL) << "LoadNativeLibrary failed for \"" << mapped_name << "\": " << reason;
     }
   }
@@ -1213,8 +1226,8 @@
     method->SetEntryPointFromPortableCompiledCode(nullptr);
     method->SetEntryPointFromQuickCompiledCode(nullptr);
   } else {
-    method->SetEntryPointFromPortableCompiledCode(class_linker->GetPortableImtConflictTrampoline());
-    method->SetEntryPointFromQuickCompiledCode(class_linker->GetQuickImtConflictTrampoline());
+    method->SetEntryPointFromPortableCompiledCode(GetPortableImtConflictStub());
+    method->SetEntryPointFromQuickCompiledCode(GetQuickImtConflictStub());
   }
   return method.Get();
 }
@@ -1233,8 +1246,8 @@
     method->SetEntryPointFromPortableCompiledCode(nullptr);
     method->SetEntryPointFromQuickCompiledCode(nullptr);
   } else {
-    method->SetEntryPointFromPortableCompiledCode(class_linker->GetPortableResolutionTrampoline());
-    method->SetEntryPointFromQuickCompiledCode(class_linker->GetQuickResolutionTrampoline());
+    method->SetEntryPointFromPortableCompiledCode(GetPortableResolutionStub());
+    method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionStub());
   }
   return method.Get();
 }
@@ -1451,9 +1464,10 @@
   instruction_set += GetInstructionSetString(kRuntimeISA);
   argv->push_back(instruction_set);
 
-  std::string features("--instruction-set-features=");
-  features += GetDefaultInstructionSetFeatures();
-  argv->push_back(features);
+  std::unique_ptr<const InstructionSetFeatures> features(InstructionSetFeatures::FromCppDefines());
+  std::string feature_string("--instruction-set-features=");
+  feature_string += features->GetFeatureString();
+  argv->push_back(feature_string);
 }
 
 void Runtime::UpdateProfilerState(int state) {
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 30dabe7..bfa7d72 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -177,10 +177,7 @@
 
   // Aborts semi-cleanly. Used in the implementation of LOG(FATAL), which most
   // callers should prefer.
-  // This isn't marked ((noreturn)) because then gcc will merge multiple calls
-  // in a single function together. This reduces code size slightly, but means
-  // that the native stack trace we get may point at the wrong call site.
-  static void Abort() NO_RETURN LOCKS_EXCLUDED(Locks::abort_lock_);
+  [[noreturn]] static void Abort() LOCKS_EXCLUDED(Locks::abort_lock_);
 
   // Returns the "main" ThreadGroup, used when attaching user threads.
   jobject GetMainThreadGroup() const;
@@ -486,10 +483,6 @@
     return target_sdk_version_;
   }
 
-  static const char* GetDefaultInstructionSetFeatures() {
-    return kDefaultInstructionSetFeatures;
-  }
-
  private:
   static void InitPlatformSignalHandlers();
 
@@ -509,8 +502,6 @@
   // A pointer to the active runtime or NULL.
   static Runtime* instance_;
 
-  static const char* kDefaultInstructionSetFeatures;
-
   // NOTE: these must match the gc::ProcessState values as they come directly from the framework.
   static constexpr int kProfileForground = 0;
   static constexpr int kProfileBackgrouud = 1;
@@ -644,14 +635,16 @@
   bool implicit_so_checks_;         // StackOverflow checks are implicit.
   bool implicit_suspend_checks_;    // Thread suspension checks are implicit.
 
-  // The filename to the native bridge library. If this is not empty the native bridge will be
-  // initialized and loaded from the given file (initialized and available). An empty value means
-  // that there's no native bridge (initialized but not available).
+  // Whether or not a native bridge has been loaded.
   //
   // The native bridge allows running native code compiled for a foreign ISA. The way it works is,
   // if standard dlopen fails to load native library associated with native activity, it calls to
   // the native bridge to load it and then gets the trampoline for the entry to native activity.
-  std::string native_bridge_library_filename_;
+  //
+  // The option 'native_bridge_library_filename' specifies the name of the native bridge.
+  // When non-empty the native bridge will be loaded from the given file. An empty value means
+  // that there's no native bridge.
+  bool is_native_bridge_loaded_;
 
   DISALLOW_COPY_AND_ASSIGN(Runtime);
 };
diff --git a/runtime/runtime_android.cc b/runtime/runtime_android.cc
index 079d7e5..33600dd 100644
--- a/runtime/runtime_android.cc
+++ b/runtime/runtime_android.cc
@@ -32,13 +32,12 @@
 
 struct sigaction old_action;
 void HandleUnexpectedSignal(int signal_number, siginfo_t* info, void* raw_context) {
-  static bool handlingUnexpectedSignal = false;
-  if (handlingUnexpectedSignal) {
-    LogMessageData data(__FILE__, __LINE__, INTERNAL_FATAL, -1);
-    LogMessage::LogLine(data, "HandleUnexpectedSignal reentered\n");
+  static bool handling_unexpected_signal = false;
+  if (handling_unexpected_signal) {
+    LogMessage::LogLine(__FILE__, __LINE__, INTERNAL_FATAL, "HandleUnexpectedSignal reentered\n");
     _exit(1);
   }
-  handlingUnexpectedSignal = true;
+  handling_unexpected_signal = true;
   gAborting++;  // set before taking any locks
   MutexLock mu(Thread::Current(), *Locks::unexpected_signal_lock_);
 
diff --git a/runtime/runtime_linux.cc b/runtime/runtime_linux.cc
index 46ee274..1de035c 100644
--- a/runtime/runtime_linux.cc
+++ b/runtime/runtime_linux.cc
@@ -21,6 +21,9 @@
 #include <sys/utsname.h>
 #include <inttypes.h>
 
+#include <sstream>
+
+#include "base/dumpable.h"
 #include "base/logging.h"
 #include "base/mutex.h"
 #include "base/stringprintf.h"
@@ -32,13 +35,13 @@
 static constexpr bool kDumpHeapObjectOnSigsevg = false;
 
 struct Backtrace {
-  void Dump(std::ostream& os) {
+  void Dump(std::ostream& os) const {
     DumpNativeStack(os, GetTid(), "\t");
   }
 };
 
 struct OsInfo {
-  void Dump(std::ostream& os) {
+  void Dump(std::ostream& os) const {
     utsname info;
     uname(&info);
     // Linux 2.6.38.8-gg784 (x86_64)
@@ -132,9 +135,11 @@
 }
 
 struct UContext {
-  explicit UContext(void* raw_context) : context(reinterpret_cast<ucontext_t*>(raw_context)->uc_mcontext) {}
+  explicit UContext(void* raw_context) :
+      context(reinterpret_cast<ucontext_t*>(raw_context)->uc_mcontext) {
+  }
 
-  void Dump(std::ostream& os) {
+  void Dump(std::ostream& os) const {
     // TODO: support non-x86 hosts (not urgent because this code doesn't run on targets).
 #if defined(__APPLE__) && defined(__i386__)
     DumpRegister32(os, "eax", context->__ss.__eax);
@@ -228,15 +233,15 @@
 #endif
   }
 
-  void DumpRegister32(std::ostream& os, const char* name, uint32_t value) {
+  void DumpRegister32(std::ostream& os, const char* name, uint32_t value) const {
     os << StringPrintf(" %6s: 0x%08x", name, value);
   }
 
-  void DumpRegister64(std::ostream& os, const char* name, uint64_t value) {
+  void DumpRegister64(std::ostream& os, const char* name, uint64_t value) const {
     os << StringPrintf(" %6s: 0x%016" PRIx64, name, value);
   }
 
-  void DumpX86Flags(std::ostream& os, uint32_t flags) {
+  void DumpX86Flags(std::ostream& os, uint32_t flags) const {
     os << " [";
     if ((flags & (1 << 0)) != 0) {
       os << " CF";
@@ -274,8 +279,7 @@
 void HandleUnexpectedSignal(int signal_number, siginfo_t* info, void* raw_context) {
   static bool handlingUnexpectedSignal = false;
   if (handlingUnexpectedSignal) {
-    LogMessageData data(__FILE__, __LINE__, INTERNAL_FATAL, -1);
-    LogMessage::LogLine(data, "HandleUnexpectedSignal reentered\n");
+    LogMessage::LogLine(__FILE__, __LINE__, INTERNAL_FATAL, "HandleUnexpectedSignal reentered\n");
     _exit(1);
   }
   handlingUnexpectedSignal = true;
diff --git a/runtime/signal_catcher.cc b/runtime/signal_catcher.cc
index 336340e..d4ec803 100644
--- a/runtime/signal_catcher.cc
+++ b/runtime/signal_catcher.cc
@@ -25,6 +25,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <sstream>
+
 #include "base/unix_file/fd_file.h"
 #include "class_linker.h"
 #include "gc/heap.h"
@@ -131,7 +133,7 @@
 
   runtime->DumpForSigQuit(os);
 
-  if (false) {
+  if ((false)) {
     std::string maps;
     if (ReadFileToString("/proc/self/maps", &maps)) {
       os << "/proc/self/maps:\n" << maps;
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 008941f..0cdc984 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -18,6 +18,7 @@
 
 #include "arch/context.h"
 #include "base/hex_dump.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/object.h"
@@ -119,7 +120,7 @@
   } else if (m->IsNative()) {
     if (cur_quick_frame_ != nullptr) {
       HandleScope* hs = reinterpret_cast<HandleScope*>(
-          reinterpret_cast<char*>(cur_quick_frame_) + m->GetHandleScopeOffsetInBytes());
+          reinterpret_cast<char*>(cur_quick_frame_) + m->GetHandleScopeOffset().SizeValue());
       return hs->GetReference(0);
     } else {
       return cur_shadow_frame_->GetVRegReference(0);
@@ -143,7 +144,7 @@
 
 size_t StackVisitor::GetNativePcOffset() const {
   DCHECK(!IsShadowFrame());
-  return GetMethod()->NativePcOffset(cur_quick_frame_pc_);
+  return GetMethod()->NativeQuickPcOffset(cur_quick_frame_pc_);
 }
 
 bool StackVisitor::GetVReg(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind,
@@ -394,14 +395,14 @@
 uintptr_t StackVisitor::GetReturnPc() const {
   uint8_t* sp = reinterpret_cast<uint8_t*>(GetCurrentQuickFrame());
   DCHECK(sp != NULL);
-  uint8_t* pc_addr = sp + GetMethod()->GetReturnPcOffsetInBytes();
+  uint8_t* pc_addr = sp + GetMethod()->GetReturnPcOffset().SizeValue();
   return *reinterpret_cast<uintptr_t*>(pc_addr);
 }
 
 void StackVisitor::SetReturnPc(uintptr_t new_ret_pc) {
   uint8_t* sp = reinterpret_cast<uint8_t*>(GetCurrentQuickFrame());
   CHECK(sp != NULL);
-  uint8_t* pc_addr = sp + GetMethod()->GetReturnPcOffsetInBytes();
+  uint8_t* pc_addr = sp + GetMethod()->GetReturnPcOffset().SizeValue();
   *reinterpret_cast<uintptr_t*>(pc_addr) = new_ret_pc;
 }
 
@@ -509,7 +510,7 @@
       // const size_t kMaxExpectedFrameSize = (256 + 2 + 3 + 3) * sizeof(word);
       const size_t kMaxExpectedFrameSize = 2 * KB;
       CHECK_LE(frame_size, kMaxExpectedFrameSize);
-      size_t return_pc_offset = method->GetReturnPcOffsetInBytes();
+      size_t return_pc_offset = method->GetReturnPcOffset().SizeValue();
       CHECK_LT(return_pc_offset, frame_size);
     }
   }
@@ -525,7 +526,7 @@
        current_fragment = current_fragment->GetLink()) {
     cur_shadow_frame_ = current_fragment->GetTopShadowFrame();
     cur_quick_frame_ = current_fragment->GetTopQuickFrame();
-    cur_quick_frame_pc_ = current_fragment->GetTopQuickFramePc();
+    cur_quick_frame_pc_ = 0;
 
     if (cur_quick_frame_ != NULL) {  // Handle quick stack frames.
       // Can't be both a shadow and a quick fragment.
@@ -543,13 +544,13 @@
         }
         size_t frame_size = method->GetFrameSizeInBytes();
         // Compute PC for next stack frame from return PC.
-        size_t return_pc_offset = method->GetReturnPcOffsetInBytes(frame_size);
+        size_t return_pc_offset = method->GetReturnPcOffset(frame_size).SizeValue();
         uint8_t* return_pc_addr = reinterpret_cast<uint8_t*>(cur_quick_frame_) + return_pc_offset;
         uintptr_t return_pc = *reinterpret_cast<uintptr_t*>(return_pc_addr);
         if (UNLIKELY(exit_stubs_installed)) {
           // While profiling, the return pc is restored from the side stack, except when walking
           // the stack for an exception where the side stack will be unwound in VisitFrame.
-          if (GetQuickInstrumentationExitPc() == return_pc) {
+          if (reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc()) == return_pc) {
             const instrumentation::InstrumentationStackFrame& instrumentation_frame =
                 GetInstrumentationStackFrame(thread_, instrumentation_stack_depth);
             instrumentation_stack_depth++;
diff --git a/runtime/stack.h b/runtime/stack.h
index 25e50a1..2f8df61 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -360,7 +360,7 @@
 class PACKED(4) ManagedStack {
  public:
   ManagedStack()
-      : link_(NULL), top_shadow_frame_(NULL), top_quick_frame_(NULL), top_quick_frame_pc_(0) {}
+      : top_quick_frame_(nullptr), link_(nullptr), top_shadow_frame_(nullptr) {}
 
   void PushManagedStackFragment(ManagedStack* fragment) {
     // Copy this top fragment into given fragment.
@@ -386,29 +386,16 @@
   }
 
   void SetTopQuickFrame(StackReference<mirror::ArtMethod>* top) {
-    DCHECK(top_shadow_frame_ == NULL);
+    DCHECK(top_shadow_frame_ == nullptr);
     top_quick_frame_ = top;
   }
 
-  uintptr_t GetTopQuickFramePc() const {
-    return top_quick_frame_pc_;
-  }
-
-  void SetTopQuickFramePc(uintptr_t pc) {
-    DCHECK(top_shadow_frame_ == NULL);
-    top_quick_frame_pc_ = pc;
-  }
-
   static size_t TopQuickFrameOffset() {
     return OFFSETOF_MEMBER(ManagedStack, top_quick_frame_);
   }
 
-  static size_t TopQuickFramePcOffset() {
-    return OFFSETOF_MEMBER(ManagedStack, top_quick_frame_pc_);
-  }
-
   ShadowFrame* PushShadowFrame(ShadowFrame* new_top_frame) {
-    DCHECK(top_quick_frame_ == NULL);
+    DCHECK(top_quick_frame_ == nullptr);
     ShadowFrame* old_frame = top_shadow_frame_;
     top_shadow_frame_ = new_top_frame;
     new_top_frame->SetLink(old_frame);
@@ -416,8 +403,8 @@
   }
 
   ShadowFrame* PopShadowFrame() {
-    DCHECK(top_quick_frame_ == NULL);
-    CHECK(top_shadow_frame_ != NULL);
+    DCHECK(top_quick_frame_ == nullptr);
+    CHECK(top_shadow_frame_ != nullptr);
     ShadowFrame* frame = top_shadow_frame_;
     top_shadow_frame_ = frame->GetLink();
     return frame;
@@ -428,7 +415,7 @@
   }
 
   void SetTopShadowFrame(ShadowFrame* top) {
-    DCHECK(top_quick_frame_ == NULL);
+    DCHECK(top_quick_frame_ == nullptr);
     top_shadow_frame_ = top;
   }
 
@@ -441,10 +428,9 @@
   bool ShadowFramesContain(StackReference<mirror::Object>* shadow_frame_entry) const;
 
  private:
+  StackReference<mirror::ArtMethod>* top_quick_frame_;
   ManagedStack* link_;
   ShadowFrame* top_shadow_frame_;
-  StackReference<mirror::ArtMethod>* top_quick_frame_;
-  uintptr_t top_quick_frame_pc_;
 };
 
 class StackVisitor {
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index 9b49d31..b1c46a9 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -88,6 +88,7 @@
     kNone,
     kInStack,
     kInRegister,
+    kInFpuRegister,
     kConstant
   };
 
diff --git a/runtime/thread.cc b/runtime/thread.cc
index b0c8fe1..9c04133 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -29,9 +29,11 @@
 #include <cerrno>
 #include <iostream>
 #include <list>
+#include <sstream>
 
 #include "arch/context.h"
 #include "base/mutex.h"
+#include "base/to_str.h"
 #include "class_linker-inl.h"
 #include "class_linker.h"
 #include "debugger.h"
@@ -409,6 +411,11 @@
     }
   }
 
+  {
+    ScopedObjectAccess soa(self);
+    Dbg::PostThreadStart(self);
+  }
+
   return self;
 }
 
@@ -947,10 +954,36 @@
 }
 
 void Thread::DumpJavaStack(std::ostream& os) const {
+  // Dumping the Java stack involves the verifier for locks. The verifier operates under the
+  // assumption that there is no exception pending on entry. Thus, stash any pending exception.
+  // TODO: Find a way to avoid const_cast.
+  StackHandleScope<3> scope(const_cast<Thread*>(this));
+  Handle<mirror::Throwable> exc;
+  Handle<mirror::Object> throw_location_this_object;
+  Handle<mirror::ArtMethod> throw_location_method;
+  uint32_t throw_location_dex_pc;
+  bool have_exception = false;
+  if (IsExceptionPending()) {
+    ThrowLocation exc_location;
+    exc = scope.NewHandle(GetException(&exc_location));
+    throw_location_this_object = scope.NewHandle(exc_location.GetThis());
+    throw_location_method = scope.NewHandle(exc_location.GetMethod());
+    throw_location_dex_pc = exc_location.GetDexPc();
+    const_cast<Thread*>(this)->ClearException();
+    have_exception = true;
+  }
+
   std::unique_ptr<Context> context(Context::Create());
   StackDumpVisitor dumper(os, const_cast<Thread*>(this), context.get(),
                           !tls32_.throwing_OutOfMemoryError);
   dumper.WalkStack();
+
+  if (have_exception) {
+    ThrowLocation exc_location(throw_location_this_object.Get(),
+                               throw_location_method.Get(),
+                               throw_location_dex_pc);
+    const_cast<Thread*>(this)->SetException(exc_location, exc.Get());
+  }
 }
 
 void Thread::DumpStack(std::ostream& os) const {
@@ -1786,7 +1819,6 @@
   DO_THREAD_OFFSET(StackEndOffset<ptr_size>(), "stack_end")
   DO_THREAD_OFFSET(ThinLockIdOffset<ptr_size>(), "thin_lock_thread_id")
   DO_THREAD_OFFSET(TopOfManagedStackOffset<ptr_size>(), "top_quick_frame_method")
-  DO_THREAD_OFFSET(TopOfManagedStackPcOffset<ptr_size>(), "top_quick_frame_pc")
   DO_THREAD_OFFSET(TopShadowFrameOffset<ptr_size>(), "top_shadow_frame")
   DO_THREAD_OFFSET(TopHandleScopeOffset<ptr_size>(), "top_handle_scope")
   DO_THREAD_OFFSET(ThreadSuspendTriggerOffset<ptr_size>(), "suspend_trigger")
@@ -2082,7 +2114,7 @@
       if (m->IsOptimized()) {
         Runtime* runtime = Runtime::Current();
         const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(m);
-        uintptr_t native_pc_offset = m->NativePcOffset(GetCurrentQuickFramePc(), entry_point);
+        uintptr_t native_pc_offset = m->NativeQuickPcOffset(GetCurrentQuickFramePc(), entry_point);
         StackMap map = m->GetStackMap(native_pc_offset);
         MemoryRegion mask = map.GetStackMask();
         for (size_t i = 0; i < mask.size_in_bits(); ++i) {
@@ -2111,7 +2143,7 @@
         if (num_regs > 0) {
           Runtime* runtime = Runtime::Current();
           const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(m);
-          uintptr_t native_pc_offset = m->NativePcOffset(GetCurrentQuickFramePc(), entry_point);
+          uintptr_t native_pc_offset = m->NativeQuickPcOffset(GetCurrentQuickFramePc(), entry_point);
           const uint8_t* reg_bitmap = map.FindBitMap(native_pc_offset);
           DCHECK(reg_bitmap != nullptr);
           const void* code_pointer = mirror::ArtMethod::EntryPointToCodePointer(entry_point);
diff --git a/runtime/thread.h b/runtime/thread.h
index b0be841..694dbda 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -144,6 +144,9 @@
   // Reset internal state of child thread after fork.
   void InitAfterFork();
 
+  // Get the currently executing thread, frequently referred to as 'self'. This call has reasonably
+  // high cost and so we favor passing self around when possible.
+  // TODO: mark as PURE so the compiler may coalesce and remove?
   static Thread* Current();
 
   // On a runnable thread, check for pending thread suspension request and handle if pending.
@@ -362,9 +365,8 @@
 
   ThrowLocation GetCurrentLocationForThrow() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void SetTopOfStack(StackReference<mirror::ArtMethod>* top_method, uintptr_t pc) {
+  void SetTopOfStack(StackReference<mirror::ArtMethod>* top_method) {
     tlsPtr_.managed_stack.SetTopQuickFrame(top_method);
-    tlsPtr_.managed_stack.SetTopQuickFramePc(pc);
   }
 
   void SetTopOfShadowStack(ShadowFrame* top) {
@@ -634,13 +636,6 @@
         ManagedStack::TopQuickFrameOffset());
   }
 
-  template<size_t pointer_size>
-  static ThreadOffset<pointer_size> TopOfManagedStackPcOffset() {
-    return ThreadOffsetFromTlsPtr<pointer_size>(
-        OFFSETOF_MEMBER(tls_ptr_sized_values, managed_stack) +
-        ManagedStack::TopQuickFramePcOffset());
-  }
-
   const ManagedStack* GetManagedStack() const {
     return &tlsPtr_.managed_stack;
   }
diff --git a/runtime/thread_linux.cc b/runtime/thread_linux.cc
index 1254056..0284364 100644
--- a/runtime/thread_linux.cc
+++ b/runtime/thread_linux.cc
@@ -16,6 +16,8 @@
 
 #include "thread.h"
 
+#include <signal.h>
+
 namespace art {
 
 void Thread::SetNativePriority(int) {
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index f714c13..f8c8fdb 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -25,6 +25,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <sstream>
+
 #include "base/mutex.h"
 #include "base/mutex-inl.h"
 #include "base/timing_logger.h"
@@ -34,6 +36,7 @@
 #include "monitor.h"
 #include "scoped_thread_state_change.h"
 #include "thread.h"
+#include "trace.h"
 #include "utils.h"
 #include "well_known_classes.h"
 
@@ -479,17 +482,18 @@
   VLOG(threads) << "Resume(" << reinterpret_cast<void*>(thread) << ") complete";
 }
 
-static void ThreadSuspendByPeerWarning(Thread* self, int level, const char* message, jobject peer) {
+static void ThreadSuspendByPeerWarning(Thread* self, LogSeverity severity, const char* message,
+                                       jobject peer) {
   JNIEnvExt* 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(level) << message << ": " << peer;
+      LOG(severity) << message << ": " << peer;
       env->ExceptionClear();
   } else {
-      LOG(level) << message << ": " << peer << ":" << scoped_name_chars.c_str();
+      LOG(severity) << message << ": " << peer << ":" << scoped_name_chars.c_str();
   }
 }
 
@@ -561,8 +565,9 @@
   }
 }
 
-static void ThreadSuspendByThreadIdWarning(int level, const char* message, uint32_t thread_id) {
-  LOG(level) << StringPrintf("%s: %d", message, thread_id);
+static void ThreadSuspendByThreadIdWarning(LogSeverity severity, const char* message,
+                                           uint32_t thread_id) {
+  LOG(severity) << StringPrintf("%s: %d", message, thread_id);
 }
 
 Thread* ThreadList::SuspendThreadByThreadId(uint32_t thread_id, bool debug_suspension,
@@ -927,6 +932,9 @@
   // suspend and so on, must happen at this point, and not in ~Thread.
   self->Destroy();
 
+  // If tracing, remember thread id and name before thread exits.
+  Trace::StoreExitingThreadInfo(self);
+
   uint32_t thin_lock_id = self->GetThreadId();
   while (self != nullptr) {
     // Remove and delete the Thread* while holding the thread_list_lock_ and
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 027f62d..b3158a4 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -18,6 +18,9 @@
 
 #include <sys/uio.h>
 
+#define ATRACE_TAG ATRACE_TAG_DALVIK
+#include "cutils/trace.h"
+
 #include "base/stl_util.h"
 #include "base/unix_file/fd_file.h"
 #include "class_linker.h"
@@ -706,9 +709,21 @@
 
 void Trace::DumpThreadList(std::ostream& os) {
   Thread* self = Thread::Current();
+  for (auto it : exited_threads_) {
+    os << it.first << "\t" << it.second << "\n";
+  }
   Locks::thread_list_lock_->AssertNotHeld(self);
   MutexLock mu(self, *Locks::thread_list_lock_);
   Runtime::Current()->GetThreadList()->ForEach(DumpThread, &os);
 }
 
+void Trace::StoreExitingThreadInfo(Thread* thread) {
+  MutexLock mu(thread, *Locks::trace_lock_);
+  if (the_trace_ != nullptr) {
+    std::string name;
+    thread->GetThreadName(name);
+    the_trace_->exited_threads_.Put(thread->GetTid(), name);
+  }
+}
+
 }  // namespace art
diff --git a/runtime/trace.h b/runtime/trace.h
index 45a02da..ead1c29 100644
--- a/runtime/trace.h
+++ b/runtime/trace.h
@@ -104,6 +104,8 @@
   static std::vector<mirror::ArtMethod*>* AllocStackTrace();
   // Clear and store an old stack trace for later use.
   static void FreeStackTrace(std::vector<mirror::ArtMethod*>* stack_trace);
+  // Save id and name of a thread before it exits.
+  static void StoreExitingThreadInfo(Thread* thread);
 
  private:
   explicit Trace(File* trace_file, int buffer_size, int flags, bool sampling_enabled);
@@ -166,6 +168,9 @@
   // Did we overflow the buffer recording traces?
   bool overflow_;
 
+  // Map of thread ids and names that have already exited.
+  SafeMap<pid_t, std::string> exited_threads_;
+
   DISALLOW_COPY_AND_ASSIGN(Trace);
 };
 
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 0688c1a..9c94f6c 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -963,7 +963,7 @@
   return IsValidClassName<kDescriptor, '/'>(s);
 }
 
-void Split(const std::string& s, char separator, std::vector<std::string>& result) {
+void Split(const std::string& s, char separator, std::vector<std::string>* result) {
   const char* p = s.data();
   const char* end = p + s.size();
   while (p != end) {
@@ -974,12 +974,12 @@
       while (++p != end && *p != separator) {
         // Skip to the next occurrence of the separator.
       }
-      result.push_back(std::string(start, p - start));
+      result->push_back(std::string(start, p - start));
     }
   }
 }
 
-std::string Trim(std::string s) {
+std::string Trim(const std::string& s) {
   std::string result;
   unsigned int start_index = 0;
   unsigned int end_index = s.size() - 1;
@@ -1009,7 +1009,7 @@
 }
 
 template <typename StringT>
-std::string Join(std::vector<StringT>& strings, char separator) {
+std::string Join(const std::vector<StringT>& strings, char separator) {
   if (strings.empty()) {
     return "";
   }
@@ -1023,9 +1023,8 @@
 }
 
 // Explicit instantiations.
-template std::string Join<std::string>(std::vector<std::string>& strings, char separator);
-template std::string Join<const char*>(std::vector<const char*>& strings, char separator);
-template std::string Join<char*>(std::vector<char*>& strings, char separator);
+template std::string Join<std::string>(const std::vector<std::string>& strings, char separator);
+template std::string Join<const char*>(const std::vector<const char*>& strings, char separator);
 
 bool StartsWith(const std::string& s, const char* prefix) {
   return s.compare(0, strlen(prefix), prefix) == 0;
@@ -1087,7 +1086,7 @@
   stats = stats.substr(stats.find(')') + 2);
   // Extract the three fields we care about.
   std::vector<std::string> fields;
-  Split(stats, ' ', fields);
+  Split(stats, ' ', &fields);
   *state = fields[0][0];
   *utime = strtoull(fields[11].c_str(), NULL, 10);
   *stime = strtoull(fields[12].c_str(), NULL, 10);
@@ -1104,12 +1103,12 @@
     return "";
   }
   std::vector<std::string> cgroup_lines;
-  Split(cgroup_file, '\n', cgroup_lines);
+  Split(cgroup_file, '\n', &cgroup_lines);
   for (size_t i = 0; i < cgroup_lines.size(); ++i) {
     std::vector<std::string> cgroup_fields;
-    Split(cgroup_lines[i], ':', cgroup_fields);
+    Split(cgroup_lines[i], ':', &cgroup_fields);
     std::vector<std::string> cgroups;
-    Split(cgroup_fields[1], ',', cgroups);
+    Split(cgroup_fields[1], ',', &cgroups);
     for (size_t i = 0; i < cgroups.size(); ++i) {
       if (cgroups[i] == "cpu") {
         return cgroup_fields[2].substr(1);  // Skip the leading slash.
@@ -1154,7 +1153,7 @@
         }
       } else if (current_method != nullptr &&
                  Locks::mutator_lock_->IsSharedHeld(Thread::Current()) &&
-                 current_method->IsWithinQuickCode(it->pc)) {
+                 current_method->PcIsWithinQuickCode(it->pc)) {
         const void* start_of_code = current_method->GetEntryPointFromQuickCompiledCode();
         os << JniLongName(current_method) << "+"
            << (it->pc - reinterpret_cast<uintptr_t>(start_of_code));
@@ -1189,7 +1188,7 @@
   }
 
   std::vector<std::string> kernel_stack_frames;
-  Split(kernel_stack, '\n', kernel_stack_frames);
+  Split(kernel_stack, '\n', &kernel_stack_frames);
   // We skip the last stack frame because it's always equivalent to "[<ffffffff>] 0xffffffff",
   // which looking at the source appears to be the kernel's way of saying "that's all, folks!".
   kernel_stack_frames.pop_back();
diff --git a/runtime/utils.h b/runtime/utils.h
index 53b49c8..b7daa64 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -380,13 +380,13 @@
 
 // Splits a string using the given separator character into a vector of
 // strings. Empty strings will be omitted.
-void Split(const std::string& s, char separator, std::vector<std::string>& result);
+void Split(const std::string& s, char separator, std::vector<std::string>* result);
 
 // Trims whitespace off both ends of the given string.
-std::string Trim(std::string s);
+std::string Trim(const std::string& s);
 
 // Joins a vector of strings into a single string, using the given separator.
-template <typename StringT> std::string Join(std::vector<StringT>& strings, char separator);
+template <typename StringT> std::string Join(const std::vector<StringT>& strings, char separator);
 
 // Returns the calling thread's tid. (The C libraries don't expose this.)
 pid_t GetTid();
diff --git a/runtime/utils_test.cc b/runtime/utils_test.cc
index 1b2c3ee..92323da 100644
--- a/runtime/utils_test.cc
+++ b/runtime/utils_test.cc
@@ -241,62 +241,62 @@
   expected.clear();
 
   actual.clear();
-  Split("", ':', actual);
+  Split("", ':', &actual);
   EXPECT_EQ(expected, actual);
 
   actual.clear();
-  Split(":", ':', actual);
+  Split(":", ':', &actual);
   EXPECT_EQ(expected, actual);
 
   expected.clear();
   expected.push_back("foo");
 
   actual.clear();
-  Split(":foo", ':', actual);
+  Split(":foo", ':', &actual);
   EXPECT_EQ(expected, actual);
 
   actual.clear();
-  Split("foo:", ':', actual);
+  Split("foo:", ':', &actual);
   EXPECT_EQ(expected, actual);
 
   actual.clear();
-  Split(":foo:", ':', actual);
+  Split(":foo:", ':', &actual);
   EXPECT_EQ(expected, actual);
 
   expected.push_back("bar");
 
   actual.clear();
-  Split("foo:bar", ':', actual);
+  Split("foo:bar", ':', &actual);
   EXPECT_EQ(expected, actual);
 
   actual.clear();
-  Split(":foo:bar", ':', actual);
+  Split(":foo:bar", ':', &actual);
   EXPECT_EQ(expected, actual);
 
   actual.clear();
-  Split("foo:bar:", ':', actual);
+  Split("foo:bar:", ':', &actual);
   EXPECT_EQ(expected, actual);
 
   actual.clear();
-  Split(":foo:bar:", ':', actual);
+  Split(":foo:bar:", ':', &actual);
   EXPECT_EQ(expected, actual);
 
   expected.push_back("baz");
 
   actual.clear();
-  Split("foo:bar:baz", ':', actual);
+  Split("foo:bar:baz", ':', &actual);
   EXPECT_EQ(expected, actual);
 
   actual.clear();
-  Split(":foo:bar:baz", ':', actual);
+  Split(":foo:bar:baz", ':', &actual);
   EXPECT_EQ(expected, actual);
 
   actual.clear();
-  Split("foo:bar:baz:", ':', actual);
+  Split("foo:bar:baz:", ':', &actual);
   EXPECT_EQ(expected, actual);
 
   actual.clear();
-  Split(":foo:bar:baz:", ':', actual);
+  Split(":foo:bar:baz:", ':', &actual);
   EXPECT_EQ(expected, actual);
 }
 
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 4a3c3ec..16338c4 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -18,6 +18,8 @@
 
 #include <stdlib.h>
 
+#include <sstream>
+
 #include "base/logging.h"
 #include "mirror/class.h"
 #include "ScopedLocalRef.h"
@@ -52,6 +54,7 @@
 jclass WellKnownClasses::java_lang_ThreadGroup;
 jclass WellKnownClasses::java_lang_Throwable;
 jclass WellKnownClasses::java_nio_DirectByteBuffer;
+jclass WellKnownClasses::java_util_ArrayList;
 jclass WellKnownClasses::java_util_Collections;
 jclass WellKnownClasses::libcore_util_EmptyArray;
 jclass WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk;
@@ -95,8 +98,10 @@
 jfieldID WellKnownClasses::java_lang_Thread_priority;
 jfieldID WellKnownClasses::java_lang_Thread_uncaughtHandler;
 jfieldID WellKnownClasses::java_lang_Thread_nativePeer;
+jfieldID WellKnownClasses::java_lang_ThreadGroup_groups;
 jfieldID WellKnownClasses::java_lang_ThreadGroup_mainThreadGroup;
 jfieldID WellKnownClasses::java_lang_ThreadGroup_name;
+jfieldID WellKnownClasses::java_lang_ThreadGroup_parent;
 jfieldID WellKnownClasses::java_lang_ThreadGroup_systemThreadGroup;
 jfieldID WellKnownClasses::java_lang_Throwable_cause;
 jfieldID WellKnownClasses::java_lang_Throwable_detailMessage;
@@ -108,6 +113,8 @@
 jfieldID WellKnownClasses::java_lang_reflect_Proxy_h;
 jfieldID WellKnownClasses::java_nio_DirectByteBuffer_capacity;
 jfieldID WellKnownClasses::java_nio_DirectByteBuffer_effectiveDirectAddress;
+jfieldID WellKnownClasses::java_util_ArrayList_array;
+jfieldID WellKnownClasses::java_util_ArrayList_size;
 jfieldID WellKnownClasses::java_util_Collections_EMPTY_LIST;
 jfieldID WellKnownClasses::libcore_util_EmptyArray_STACK_TRACE_ELEMENT;
 jfieldID WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_data;
@@ -187,6 +194,7 @@
   java_lang_ThreadGroup = CacheClass(env, "java/lang/ThreadGroup");
   java_lang_Throwable = CacheClass(env, "java/lang/Throwable");
   java_nio_DirectByteBuffer = CacheClass(env, "java/nio/DirectByteBuffer");
+  java_util_ArrayList = CacheClass(env, "java/util/ArrayList");
   java_util_Collections = CacheClass(env, "java/util/Collections");
   libcore_util_EmptyArray = CacheClass(env, "libcore/util/EmptyArray");
   org_apache_harmony_dalvik_ddmc_Chunk = CacheClass(env, "org/apache/harmony/dalvik/ddmc/Chunk");
@@ -225,8 +233,10 @@
   java_lang_Thread_priority = CacheField(env, java_lang_Thread, false, "priority", "I");
   java_lang_Thread_uncaughtHandler = CacheField(env, java_lang_Thread, false, "uncaughtHandler", "Ljava/lang/Thread$UncaughtExceptionHandler;");
   java_lang_Thread_nativePeer = CacheField(env, java_lang_Thread, false, "nativePeer", "J");
+  java_lang_ThreadGroup_groups = CacheField(env, java_lang_ThreadGroup, false, "groups", "Ljava/util/List;");
   java_lang_ThreadGroup_mainThreadGroup = CacheField(env, java_lang_ThreadGroup, true, "mainThreadGroup", "Ljava/lang/ThreadGroup;");
   java_lang_ThreadGroup_name = CacheField(env, java_lang_ThreadGroup, false, "name", "Ljava/lang/String;");
+  java_lang_ThreadGroup_parent = CacheField(env, java_lang_ThreadGroup, false, "parent", "Ljava/lang/ThreadGroup;");
   java_lang_ThreadGroup_systemThreadGroup = CacheField(env, java_lang_ThreadGroup, true, "systemThreadGroup", "Ljava/lang/ThreadGroup;");
   java_lang_Throwable_cause = CacheField(env, java_lang_Throwable, false, "cause", "Ljava/lang/Throwable;");
   java_lang_Throwable_detailMessage = CacheField(env, java_lang_Throwable, false, "detailMessage", "Ljava/lang/String;");
@@ -238,6 +248,8 @@
   java_lang_reflect_Proxy_h = CacheField(env, java_lang_reflect_Proxy, false, "h", "Ljava/lang/reflect/InvocationHandler;");
   java_nio_DirectByteBuffer_capacity = CacheField(env, java_nio_DirectByteBuffer, false, "capacity", "I");
   java_nio_DirectByteBuffer_effectiveDirectAddress = CacheField(env, java_nio_DirectByteBuffer, false, "effectiveDirectAddress", "J");
+  java_util_ArrayList_array = CacheField(env, java_util_ArrayList, false, "array", "[Ljava/lang/Object;");
+  java_util_ArrayList_size = CacheField(env, java_util_ArrayList, false, "size", "I");
   java_util_Collections_EMPTY_LIST = CacheField(env, java_util_Collections, true, "EMPTY_LIST", "Ljava/util/List;");
   libcore_util_EmptyArray_STACK_TRACE_ELEMENT = CacheField(env, libcore_util_EmptyArray, true, "STACK_TRACE_ELEMENT", "[Ljava/lang/StackTraceElement;");
   org_apache_harmony_dalvik_ddmc_Chunk_data = CacheField(env, org_apache_harmony_dalvik_ddmc_Chunk, false, "data", "[B");
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index 790d7f7..d651b90 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -64,6 +64,7 @@
   static jclass java_lang_ThreadGroup;
   static jclass java_lang_Thread__UncaughtExceptionHandler;
   static jclass java_lang_Throwable;
+  static jclass java_util_ArrayList;
   static jclass java_util_Collections;
   static jclass java_nio_DirectByteBuffer;
   static jclass libcore_util_EmptyArray;
@@ -111,8 +112,10 @@
   static jfieldID java_lang_Thread_priority;
   static jfieldID java_lang_Thread_uncaughtHandler;
   static jfieldID java_lang_Thread_nativePeer;
+  static jfieldID java_lang_ThreadGroup_groups;
   static jfieldID java_lang_ThreadGroup_mainThreadGroup;
   static jfieldID java_lang_ThreadGroup_name;
+  static jfieldID java_lang_ThreadGroup_parent;
   static jfieldID java_lang_ThreadGroup_systemThreadGroup;
   static jfieldID java_lang_Throwable_cause;
   static jfieldID java_lang_Throwable_detailMessage;
@@ -121,6 +124,8 @@
   static jfieldID java_lang_Throwable_suppressedExceptions;
   static jfieldID java_nio_DirectByteBuffer_capacity;
   static jfieldID java_nio_DirectByteBuffer_effectiveDirectAddress;
+  static jfieldID java_util_ArrayList_array;
+  static jfieldID java_util_ArrayList_size;
   static jfieldID java_util_Collections_EMPTY_LIST;
   static jfieldID libcore_util_EmptyArray_STACK_TRACE_ELEMENT;
   static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_data;
diff --git a/sigchainlib/Android.mk b/sigchainlib/Android.mk
index d86735d..b7ff360 100644
--- a/sigchainlib/Android.mk
+++ b/sigchainlib/Android.mk
@@ -22,14 +22,26 @@
 LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
 LOCAL_MODULE_TAGS := optional
 LOCAL_CFLAGS += $(ART_TARGET_CFLAGS)
-LOCAL_SRC_FILES := sigchain.cc
+LOCAL_SRC_FILES := sigchain_dummy.cc
 LOCAL_CLANG = $(ART_TARGET_CLANG)
 LOCAL_MODULE:= libsigchain
-LOCAL_SHARED_LIBRARIES := liblog libdl
+LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.common_build.mk
 include $(BUILD_SHARED_LIBRARY)
 
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS += $(ART_TARGET_CFLAGS)
+LOCAL_SRC_FILES := sigchain.cc
+LOCAL_CLANG = $(ART_TARGET_CLANG)
+LOCAL_MODULE:= libsigchain
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.common_build.mk
+include $(BUILD_STATIC_LIBRARY)
+
 # Build host library.
 include $(CLEAR_VARS)
 LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
@@ -37,9 +49,23 @@
 LOCAL_IS_HOST_MODULE := true
 LOCAL_CFLAGS += $(ART_HOST_CFLAGS)
 LOCAL_CLANG = $(ART_HOST_CLANG)
+LOCAL_SRC_FILES := sigchain_dummy.cc
+LOCAL_MODULE:= libsigchain
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+LOCAL_LDLIBS = -ldl
+LOCAL_MULTILIB := both
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
+LOCAL_MODULE_TAGS := optional
+LOCAL_IS_HOST_MODULE := true
+LOCAL_CFLAGS += $(ART_HOST_CFLAGS)
+LOCAL_CLANG = $(ART_HOST_CLANG)
 LOCAL_SRC_FILES := sigchain.cc
 LOCAL_MODULE:= libsigchain
 LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 LOCAL_LDLIBS = -ldl
 LOCAL_MULTILIB := both
-include $(BUILD_HOST_SHARED_LIBRARY)
+include external/libcxx/libcxx.mk
+include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/sigchainlib/sigchain.cc b/sigchainlib/sigchain.cc
index 74bfb7e..601e321 100644
--- a/sigchainlib/sigchain.cc
+++ b/sigchainlib/sigchain.cc
@@ -35,6 +35,8 @@
 
 namespace art {
 
+typedef int (*SigActionFnPtr)(int, const struct sigaction*, struct sigaction*);
+
 class SignalAction {
  public:
   SignalAction() : claimed_(false), uses_old_style_(false) {
@@ -107,21 +109,20 @@
   }
 }
 
-
 // Claim a signal chain for a particular signal.
-void ClaimSignalChain(int signal, struct sigaction* oldaction) {
+extern "C" void ClaimSignalChain(int signal, struct sigaction* oldaction) {
   CheckSignalValid(signal);
   user_sigactions[signal].Claim(*oldaction);
 }
 
-void UnclaimSignalChain(int signal) {
+extern "C" void UnclaimSignalChain(int signal) {
   CheckSignalValid(signal);
 
   user_sigactions[signal].Unclaim(signal);
 }
 
 // Invoke the user's signal handler.
-void InvokeUserSignalHandler(int sig, siginfo_t* info, void* context) {
+extern "C" void InvokeUserSignalHandler(int sig, siginfo_t* info, void* context) {
   // Check the arguments.
   CheckSignalValid(sig);
 
@@ -148,10 +149,22 @@
   }
 }
 
-extern "C" {
-// These functions are C linkage since they replace the functions in libc.
+extern "C" void EnsureFrontOfChain(int signal, struct sigaction* expected_action) {
+  CheckSignalValid(signal);
+  // Read the current action without looking at the chain, it should be the expected action.
+  SigActionFnPtr linked_sigaction = reinterpret_cast<SigActionFnPtr>(linked_sigaction_sym);
+  struct sigaction current_action;
+  linked_sigaction(signal, nullptr, &current_action);
+  // If the sigactions don't match then we put the current action on the chain and make ourself as
+  // the main action.
+  if (current_action.sa_sigaction != expected_action->sa_sigaction) {
+    log("Warning: Unexpected sigaction action found %p\n", current_action.sa_sigaction);
+    user_sigactions[signal].Claim(current_action);
+    linked_sigaction(signal, expected_action, nullptr);
+  }
+}
 
-int sigaction(int signal, const struct sigaction* new_action, struct sigaction* old_action) {
+extern "C" int sigaction(int signal, const struct sigaction* new_action, struct sigaction* old_action) {
   // If this signal has been claimed as a signal chain, record the user's
   // action but don't pass it on to the kernel.
   // Note that we check that the signal number is in range here.  An out of range signal
@@ -181,13 +194,11 @@
     log("Unable to find next sigaction in signal chain");
     abort();
   }
-
-  typedef int (*SigAction)(int, const struct sigaction*, struct sigaction*);
-  SigAction linked_sigaction = reinterpret_cast<SigAction>(linked_sigaction_sym);
+  SigActionFnPtr linked_sigaction = reinterpret_cast<SigActionFnPtr>(linked_sigaction_sym);
   return linked_sigaction(signal, new_action, old_action);
 }
 
-sighandler_t signal(int signal, sighandler_t handler) {
+extern "C" sighandler_t signal(int signal, sighandler_t handler) {
   struct sigaction sa;
   sigemptyset(&sa.sa_mask);
   sa.sa_handler = handler;
@@ -226,7 +237,7 @@
   return reinterpret_cast<sighandler_t>(sa.sa_handler);
 }
 
-int sigprocmask(int how, const sigset_t* bionic_new_set, sigset_t* bionic_old_set) {
+extern "C" int sigprocmask(int how, const sigset_t* bionic_new_set, sigset_t* bionic_old_set) {
   const sigset_t* new_set_ptr = bionic_new_set;
   sigset_t tmpset;
   if (bionic_new_set != NULL) {
@@ -258,9 +269,8 @@
   SigProcMask linked_sigprocmask= reinterpret_cast<SigProcMask>(linked_sigprocmask_sym);
   return linked_sigprocmask(how, new_set_ptr, bionic_old_set);
 }
-}   // extern "C"
 
-void InitializeSignalChain() {
+extern "C" void InitializeSignalChain() {
   // Warning.
   // Don't call this from within a signal context as it makes calls to
   // dlsym.  Calling into the dynamic linker will result in locks being
@@ -290,5 +300,6 @@
   }
   initialized = true;
 }
+
 }   // namespace art
 
diff --git a/sigchainlib/sigchain.h b/sigchainlib/sigchain.h
index 5bc4026..79b76a7 100644
--- a/sigchainlib/sigchain.h
+++ b/sigchainlib/sigchain.h
@@ -21,14 +21,16 @@
 
 namespace art {
 
-void InitializeSignalChain();
+extern "C" void InitializeSignalChain();
 
-void ClaimSignalChain(int signal, struct sigaction* oldaction);
+extern "C" void ClaimSignalChain(int signal, struct sigaction* oldaction);
 
-void UnclaimSignalChain(int signal);
+extern "C" void UnclaimSignalChain(int signal);
 
-void InvokeUserSignalHandler(int sig, siginfo_t* info, void* context);
+extern "C" void InvokeUserSignalHandler(int sig, siginfo_t* info, void* context);
 
-}   // namespace art
+extern "C" void EnsureFrontOfChain(int signal, struct sigaction* expected_action);
+
+}  // namespace art
 
 #endif  // ART_SIGCHAINLIB_SIGCHAIN_H_
diff --git a/sigchainlib/sigchain_dummy.cc b/sigchainlib/sigchain_dummy.cc
new file mode 100644
index 0000000..17bfe8f
--- /dev/null
+++ b/sigchainlib/sigchain_dummy.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 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 <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_ANDROID_OS
+#include <android/log.h>
+#else
+#include <stdarg.h>
+#include <iostream>
+#endif
+
+#include "sigchain.h"
+
+static void log(const char* format, ...) {
+  char buf[256];
+  va_list ap;
+  va_start(ap, format);
+  vsnprintf(buf, sizeof(buf), format, ap);
+#ifdef HAVE_ANDROID_OS
+  __android_log_write(ANDROID_LOG_ERROR, "libsigchain", buf);
+#else
+  std::cout << buf << "\n";
+#endif
+  va_end(ap);
+}
+
+extern "C" void ClaimSignalChain(int signal, struct sigaction* oldaction) {
+  log("ClaimSignalChain is not exported by the main executable.");
+  abort();
+}
+
+extern "C" void UnclaimSignalChain(int signal) {
+  log("UnclaimSignalChain is not exported by the main executable.");
+  abort();
+}
+
+extern "C" void InvokeUserSignalHandler(int sig, siginfo_t* info, void* context) {
+  log("InvokeUserSignalHandler is not exported by the main executable.");
+  abort();
+}
+
+extern "C" void InitializeSignalChain() {
+  log("InitializeSignalChain is not exported by the main executable.");
+  abort();
+}
+
+extern "C" void EnsureFrontOfChain(int signal, struct sigaction* expected_action) {
+  log("EnsureFrontOfChain is not exported by the main executable.");
+  abort();
+}
diff --git a/sigchainlib/version-script.txt b/sigchainlib/version-script.txt
new file mode 100644
index 0000000..ce15054
--- /dev/null
+++ b/sigchainlib/version-script.txt
@@ -0,0 +1,13 @@
+{
+global:
+  ClaimSignalChain;
+  UnclaimSignalChain;
+  InvokeUserSignalHandler;
+  InitializeSignalChain;
+  EnsureFrontOfChain;
+  sigaction;
+  signal;
+  sigprocmask;
+local:
+  *;
+};
diff --git a/test/004-ReferenceMap/stack_walk_refmap_jni.cc b/test/004-ReferenceMap/stack_walk_refmap_jni.cc
index e914bd9..291b45f 100644
--- a/test/004-ReferenceMap/stack_walk_refmap_jni.cc
+++ b/test/004-ReferenceMap/stack_walk_refmap_jni.cc
@@ -22,7 +22,7 @@
 #define CHECK_REGS_CONTAIN_REFS(native_pc_offset, ...) do { \
   int t[] = {__VA_ARGS__}; \
   int t_size = sizeof(t) / sizeof(*t); \
-  CheckReferences(t, t_size, m->NativePcOffset(m->ToNativePc(native_pc_offset))); \
+  CheckReferences(t, t_size, m->NativeQuickPcOffset(m->ToNativeQuickPc(native_pc_offset))); \
 } while (false);
 
 struct ReferenceMap2Visitor : public CheckReferenceMapVisitor {
diff --git a/test/004-UnsafeTest/src/Main.java b/test/004-UnsafeTest/src/Main.java
index 8c8ad16..743d62c 100644
--- a/test/004-UnsafeTest/src/Main.java
+++ b/test/004-UnsafeTest/src/Main.java
@@ -25,14 +25,14 @@
   private static void check(int actual, int expected, String msg) {
     if (actual != expected) {
       System.out.println(msg + " : " + actual + " != " + expected);
-      System.exit(-1);
+      System.exit(1);
     }
   }
 
   private static void check(long actual, long expected, String msg) {
     if (actual != expected) {
       System.out.println(msg + " : " + actual + " != " + expected);
-      System.exit(-1);
+      System.exit(1);
     }
   }
 
diff --git a/test/036-finalizer/src/Main.java b/test/036-finalizer/src/Main.java
index 390472d..e3cf4ee 100644
--- a/test/036-finalizer/src/Main.java
+++ b/test/036-finalizer/src/Main.java
@@ -125,34 +125,55 @@
     }
 
     static class FinalizeCounter {
+      public static final int maxCount = 1024;
+      public static boolean finalized[] = new boolean[maxCount];
       private static Object finalizeLock = new Object();
       private static volatile int finalizeCount = 0;
       private int index;
       static int getCount() {
         return finalizeCount;
       }
+      static void printNonFinalized() {
+        for (int i = 0; i < maxCount; ++i) {
+          if (!FinalizeCounter.finalized[i]) {
+            System.err.println("Element " + i + " was not finalized");
+          }
+        }
+      }
       FinalizeCounter(int index) {
         this.index = index;
       }
       protected void finalize() {
         synchronized(finalizeLock) {
           ++finalizeCount;
+          finalized[index] = true;
         }
       }
     }
 
-    private static void runFinalizationTest() {
-      int count = 1024;
+    private static void allocFinalizableObjects(int count) {
       Object[] objs = new Object[count];
       for (int i = 0; i < count; ++i) {
         objs[i] = new FinalizeCounter(i);
       }
-      for (int i = 0; i < count; ++i) {
-        objs[i] = null;
-      }
-      System.gc();
+    }
+
+    private static void runFinalizationTest() {
+      allocFinalizableObjects(FinalizeCounter.maxCount);
+      Runtime.getRuntime().gc();
       System.runFinalization();
-      System.out.println("Finalized " + FinalizeCounter.getCount() + " / "  + count);
+      System.out.println("Finalized " + FinalizeCounter.getCount() + " / "  + FinalizeCounter.maxCount);
+      if (FinalizeCounter.getCount() != FinalizeCounter.maxCount) {
+        // Print out all the finalized elements.
+        FinalizeCounter.printNonFinalized();
+        // Try to sleep for a couple seconds to see if the objects became finalized after.
+        try {
+          java.lang.Thread.sleep(2000);
+        } catch (InterruptedException e) {
+        }
+        System.out.println("After sleep finalized " + FinalizeCounter.getCount() + " / "  + FinalizeCounter.maxCount);
+        FinalizeCounter.printNonFinalized();
+      }
     }
 
     public static class FinalizerTest {
diff --git a/test/074-gc-thrash/src/Main.java b/test/074-gc-thrash/src/Main.java
index 78413f3..32fbf2d 100644
--- a/test/074-gc-thrash/src/Main.java
+++ b/test/074-gc-thrash/src/Main.java
@@ -183,7 +183,11 @@
     }
 
     private String makeString(int val) {
-        return new String("Robin" + val);
+        try {
+            return new String("Robin" + val);
+        } catch (OutOfMemoryError e) {
+            return null;
+        }
     }
 }
 
@@ -251,58 +255,63 @@
      * valid and invalid references on the stack.
      */
     private String dive(int depth, int iteration) {
-        String str0;
-        String str1;
-        String str2;
-        String str3;
-        String str4;
-        String str5;
-        String str6;
-        String str7;
-        String funStr;
+        try {
+            String str0;
+            String str1;
+            String str2;
+            String str3;
+            String str4;
+            String str5;
+            String str6;
+            String str7;
+            String funStr = "";
+            switch (iteration % 8) {
+                case 0:
+                    funStr = str0 = makeString(iteration);
+                    break;
+                case 1:
+                    funStr = str1 = makeString(iteration);
+                    break;
+                case 2:
+                    funStr = str2 = makeString(iteration);
+                    break;
+                case 3:
+                    funStr = str3 = makeString(iteration);
+                    break;
+                case 4:
+                    funStr = str4 = makeString(iteration);
+                    break;
+                case 5:
+                    funStr = str5 = makeString(iteration);
+                    break;
+                case 6:
+                    funStr = str6 = makeString(iteration);
+                    break;
+                case 7:
+                    funStr = str7 = makeString(iteration);
+                    break;
+            }
 
-        funStr = "";
-
-        switch (iteration % 8) {
-            case 0:
-                funStr = str0 = makeString(iteration);
-                break;
-            case 1:
-                funStr = str1 = makeString(iteration);
-                break;
-            case 2:
-                funStr = str2 = makeString(iteration);
-                break;
-            case 3:
-                funStr = str3 = makeString(iteration);
-                break;
-            case 4:
-                funStr = str4 = makeString(iteration);
-                break;
-            case 5:
-                funStr = str5 = makeString(iteration);
-                break;
-            case 6:
-                funStr = str6 = makeString(iteration);
-                break;
-            case 7:
-                funStr = str7 = makeString(iteration);
-                break;
+            strong[depth] = funStr;
+            weak[depth] = new WeakReference(funStr);
+            if (depth+1 < MAX_DEPTH)
+                dive(depth+1, iteration+1);
+            else
+                Main.sleep(100);
+            return funStr;
+        } catch (OutOfMemoryError e) {
+            // Silently ignore OOME since gc stress mode causes them to occur but shouldn't be a
+            // test failure.
         }
-
-        strong[depth] = funStr;
-        weak[depth] = new WeakReference(funStr);
-
-        if (depth+1 < MAX_DEPTH)
-            dive(depth+1, iteration+1);
-        else
-            Main.sleep(100);
-
-        return funStr;
+        return "";
     }
 
     private String makeString(int val) {
-        return new String("Deep" + val);
+        try {
+            return new String("Deep" + val);
+        } catch (OutOfMemoryError e) {
+            return null;
+        }
     }
 }
 
@@ -319,13 +328,16 @@
         Main.startupDelay();
 
         while (!Main.quit) {
-            chunk = new byte[100000];
-            pretendToUse(chunk);
+            try {
+                chunk = new byte[100000];
+                pretendToUse(chunk);
 
-            count++;
-            if ((count % 500) == 0) {
-                Main.sleep(400);
-                sleepCount++;
+                count++;
+                if ((count % 500) == 0) {
+                    Main.sleep(400);
+                    sleepCount++;
+                }
+            } catch (OutOfMemoryError e) {
             }
         }
 
diff --git a/test/083-compiler-regressions/expected.txt b/test/083-compiler-regressions/expected.txt
index e907fd1..c43d1f7 100644
--- a/test/083-compiler-regressions/expected.txt
+++ b/test/083-compiler-regressions/expected.txt
@@ -16,6 +16,7 @@
 b13679511Test finishing
 b16177324TestWrapper caught NPE as expected.
 b16230771TestWrapper caught NPE as expected.
+b17969907TestWrapper caught NPE as expected.
 largeFrame passes
 largeFrameFloat passes
 mulBy1Test passes
diff --git a/test/083-compiler-regressions/src/Main.java b/test/083-compiler-regressions/src/Main.java
index 8d7bf01..9c772b9 100644
--- a/test/083-compiler-regressions/src/Main.java
+++ b/test/083-compiler-regressions/src/Main.java
@@ -38,6 +38,7 @@
         b13679511Test();
         b16177324TestWrapper();
         b16230771TestWrapper();
+        b17969907TestWrapper();
         largeFrameTest();
         largeFrameTestFloat();
         mulBy1Test();
@@ -977,6 +978,24 @@
       }
     }
 
+    static void b17969907TestWrapper() {
+      try {
+        b17969907Test();
+        System.out.println("b17969907Test unexpectedly didn't throw NPE.");
+      } catch (NullPointerException expected) {
+        System.out.println("b17969907TestWrapper caught NPE as expected.");
+      }
+    }
+
+    public static void b17969907Test() {
+      Integer i = new Integer(1);
+      int sum = 0;
+      while (sum < 100) {
+        sum += i;
+        i = null;
+      }
+    }
+
     static double TooManyArgs(
           long l00,
           long l01,
diff --git a/test/089-many-methods/check b/test/089-many-methods/check
new file mode 100755
index 0000000..594626a
--- /dev/null
+++ b/test/089-many-methods/check
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 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.
+
+# Strip build error debug messages, as they are environment-specific.
+sed -e '/^Failed to build/d' -e '/^Non-canonical tmpdir/d' -e '/^Args:/d' "$2" > "$2.tmp"
+
+diff --strip-trailing-cr -q "$1" "$2.tmp" >/dev/null
\ No newline at end of file
diff --git a/test/115-native-bridge/run b/test/115-native-bridge/run
index e475cd6..32a9975 100644
--- a/test/115-native-bridge/run
+++ b/test/115-native-bridge/run
@@ -18,9 +18,9 @@
 
 # Use libnativebridgetest as a native bridge, start NativeBridgeMain (Main is JniTest main file).
 LIBPATH=$(echo ${ARGS} | sed -r 's/.*Djava.library.path=([^ ]*) .*/\1/')
-cp ${LIBPATH}/libnativebridgetest.so .
+ln -s ${LIBPATH}/libnativebridgetest.so .
 touch libarttest.so
-cp ${LIBPATH}/libarttest.so libarttest2.so
+ln -s ${LIBPATH}/libarttest.so libarttest2.so
 
 # pwd likely has /, so it's a pain to put that into a sed rule.
 LEFT=$(echo ${ARGS} | sed -r 's/-Djava.library.path.*//')
diff --git a/test/800-smali/build b/test/124-missing-classes/build
similarity index 64%
rename from test/800-smali/build
rename to test/124-missing-classes/build
index 1b5a4e3..62e57c8 100644
--- a/test/800-smali/build
+++ b/test/124-missing-classes/build
@@ -1,6 +1,6 @@
 #!/bin/bash
 #
-# Copyright (C) 2014 The Android Open Source Project
+# 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.
@@ -17,16 +17,12 @@
 # Stop if something fails.
 set -e
 
-# Compile Java classes
 mkdir classes
+
+# Some classes are available at compile time...
 ${JAVAC} -d classes `find src -name '*.java'`
-${DX} -JXmx256m --debug --dex --output=java_classes.dex classes
 
-# Compile Smali classes
-${SMALI} -JXmx256m --output smali_classes.dex `find src -name '*.smali'`
-
-# Combine files.
-${DXMERGER} classes.dex java_classes.dex smali_classes.dex
-
-# Zip up output.
-zip $TEST_NAME.jar classes.dex
+# ...but not at run time.
+rm 'classes/MissingClass.class'
+rm 'classes/Main$MissingInnerClass.class'
+${DX} -JXmx256m --debug --dex --output=$TEST_NAME.jar classes
diff --git a/test/124-missing-classes/expected.txt b/test/124-missing-classes/expected.txt
new file mode 100644
index 0000000..ce761c3
--- /dev/null
+++ b/test/124-missing-classes/expected.txt
@@ -0,0 +1,6 @@
+Test Started
+testMissingFieldType caught NoClassDefFoundError
+testMissingMethodReturnType caught NoClassDefFoundError
+testMissingMethodParameterType caught NoClassDefFoundError
+testMissingInnerClass caught NoClassDefFoundError
+Test Finished
diff --git a/test/124-missing-classes/info.txt b/test/124-missing-classes/info.txt
new file mode 100644
index 0000000..a734f99
--- /dev/null
+++ b/test/124-missing-classes/info.txt
@@ -0,0 +1 @@
+Tests the effects of missing classes.
diff --git a/test/124-missing-classes/src/Main.java b/test/124-missing-classes/src/Main.java
new file mode 100644
index 0000000..1667d2d
--- /dev/null
+++ b/test/124-missing-classes/src/Main.java
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+public final class Main {
+
+    public static void main(String[] args) throws Exception {
+        System.out.println("Test Started");
+        testMissingFieldType();
+        testMissingMethodReturnType();
+        testMissingMethodParameterType();
+        testMissingInnerClass();
+        System.out.println("Test Finished");
+    }
+
+    private static class ClassWithMissingFieldType {
+        MissingClass field;
+    }
+
+    private static void testMissingFieldType() throws Exception {
+        try {
+            ClassWithMissingFieldType.class.getDeclaredFields();
+            throw new AssertionError();
+        } catch (NoClassDefFoundError e) {
+            System.out.println("testMissingFieldType caught NoClassDefFoundError");
+        }
+    }
+
+    private static class ClassWithMissingMethodReturnType {
+        MissingClass method() {
+            return null;
+        }
+    }
+
+    private static void testMissingMethodReturnType() throws Exception {
+        try {
+            ClassWithMissingMethodReturnType.class.getDeclaredMethods();
+            throw new AssertionError();
+        } catch (NoClassDefFoundError e) {
+            System.out.println("testMissingMethodReturnType caught NoClassDefFoundError");
+        }
+    }
+
+    private static class ClassWithMissingMethodParameterType {
+        void method(MissingClass arg) {}
+    }
+
+    private static void testMissingMethodParameterType() throws Exception {
+        try {
+            ClassWithMissingMethodParameterType.class.getDeclaredMethods();
+            throw new AssertionError();
+        } catch (NoClassDefFoundError e) {
+            System.out.println("testMissingMethodParameterType caught NoClassDefFoundError");
+        }
+    }
+
+    private static final class MissingInnerClass {
+    }
+
+    private static void testMissingInnerClass() throws Exception {
+        try {
+            Main.class.getDeclaredClasses();
+            throw new AssertionError();
+        } catch (NoClassDefFoundError e) {
+            System.out.println("testMissingInnerClass caught NoClassDefFoundError");
+        }
+    }
+}
diff --git a/runtime/log_severity.h b/test/124-missing-classes/src/MissingClass.java
similarity index 68%
rename from runtime/log_severity.h
rename to test/124-missing-classes/src/MissingClass.java
index 31682df..33aaa56 100644
--- a/runtime/log_severity.h
+++ b/test/124-missing-classes/src/MissingClass.java
@@ -14,12 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ART_RUNTIME_LOG_SEVERITY_H_
-#define ART_RUNTIME_LOG_SEVERITY_H_
-
-typedef int LogSeverity;
-
-const int VERBOSE = 0, DEBUG = 1, INFO = 2, WARNING = 3, ERROR = 4, FATAL = 5;
-const int INTERNAL_FATAL = 6;  // For Runtime::Abort.
-
-#endif  // ART_RUNTIME_LOG_SEVERITY_H_
+public final class MissingClass {
+    public static final class MissingInnerClass {
+    }
+}
diff --git a/test/125-gc-and-classloading/expected.txt b/test/125-gc-and-classloading/expected.txt
new file mode 100644
index 0000000..7ef22e9
--- /dev/null
+++ b/test/125-gc-and-classloading/expected.txt
@@ -0,0 +1 @@
+PASS
diff --git a/test/125-gc-and-classloading/info.txt b/test/125-gc-and-classloading/info.txt
new file mode 100644
index 0000000..bb6bf12
--- /dev/null
+++ b/test/125-gc-and-classloading/info.txt
@@ -0,0 +1 @@
+Tests class loading and GC running in parallel.
diff --git a/test/125-gc-and-classloading/src/Main.java b/test/125-gc-and-classloading/src/Main.java
new file mode 100644
index 0000000..61e123d
--- /dev/null
+++ b/test/125-gc-and-classloading/src/Main.java
@@ -0,0 +1,3072 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+import java.util.concurrent.CountDownLatch;
+
+public class Main {
+
+    public static void main(String[] args) throws Exception {
+        // Try to cause a class loading/linking while GC is running.
+        CountDownLatch cdl = new CountDownLatch(1);
+        GcThread gcThread = new GcThread(cdl);
+        ClassLoadingThread classLoadingThread = new ClassLoadingThread(cdl);
+        gcThread.start();
+        classLoadingThread.start();
+        gcThread.join();
+        classLoadingThread.join();
+        System.out.println("PASS");
+    }
+
+    static class GcThread extends Thread {
+        CountDownLatch cdl;
+
+        GcThread(CountDownLatch cdl) {
+            this.cdl = cdl;
+        }
+
+        public void run() {
+            for (int i = 0; i < 10; ++i) {
+                Runtime.getRuntime().gc();
+                if (i == 0) {
+                    cdl.countDown();
+                }
+            }
+        }
+    }
+
+    static class ClassLoadingThread extends Thread {
+        CountDownLatch cdl;
+
+        ClassLoadingThread(CountDownLatch cdl) {
+            this.cdl = cdl;
+        }
+
+        public void run() {
+            try {
+                cdl.await();
+                Class c0 = Class.forName("Main$BigClass");
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    // A class with lots of fields so that the class loading/linking takes a long time.
+    // It is an abstract class to exercise the non-embedded imt/vtable case.
+    static abstract class BigClass {
+        static Object sf1;
+        static Object sf2;
+        static Object sf3;
+        static Object sf4;
+        static Object sf5;
+        static Object sf6;
+        static Object sf7;
+        static Object sf8;
+        static Object sf9;
+        static Object sf10;
+        static Object sf11;
+        static Object sf12;
+        static Object sf13;
+        static Object sf14;
+        static Object sf15;
+        static Object sf16;
+        static Object sf17;
+        static Object sf18;
+        static Object sf19;
+        static Object sf20;
+        static Object sf21;
+        static Object sf22;
+        static Object sf23;
+        static Object sf24;
+        static Object sf25;
+        static Object sf26;
+        static Object sf27;
+        static Object sf28;
+        static Object sf29;
+        static Object sf30;
+        static Object sf31;
+        static Object sf32;
+        static Object sf33;
+        static Object sf34;
+        static Object sf35;
+        static Object sf36;
+        static Object sf37;
+        static Object sf38;
+        static Object sf39;
+        static Object sf40;
+        static Object sf41;
+        static Object sf42;
+        static Object sf43;
+        static Object sf44;
+        static Object sf45;
+        static Object sf46;
+        static Object sf47;
+        static Object sf48;
+        static Object sf49;
+        static Object sf50;
+        static Object sf51;
+        static Object sf52;
+        static Object sf53;
+        static Object sf54;
+        static Object sf55;
+        static Object sf56;
+        static Object sf57;
+        static Object sf58;
+        static Object sf59;
+        static Object sf60;
+        static Object sf61;
+        static Object sf62;
+        static Object sf63;
+        static Object sf64;
+        static Object sf65;
+        static Object sf66;
+        static Object sf67;
+        static Object sf68;
+        static Object sf69;
+        static Object sf70;
+        static Object sf71;
+        static Object sf72;
+        static Object sf73;
+        static Object sf74;
+        static Object sf75;
+        static Object sf76;
+        static Object sf77;
+        static Object sf78;
+        static Object sf79;
+        static Object sf80;
+        static Object sf81;
+        static Object sf82;
+        static Object sf83;
+        static Object sf84;
+        static Object sf85;
+        static Object sf86;
+        static Object sf87;
+        static Object sf88;
+        static Object sf89;
+        static Object sf90;
+        static Object sf91;
+        static Object sf92;
+        static Object sf93;
+        static Object sf94;
+        static Object sf95;
+        static Object sf96;
+        static Object sf97;
+        static Object sf98;
+        static Object sf99;
+        static Object sf100;
+        static Object sf101;
+        static Object sf102;
+        static Object sf103;
+        static Object sf104;
+        static Object sf105;
+        static Object sf106;
+        static Object sf107;
+        static Object sf108;
+        static Object sf109;
+        static Object sf110;
+        static Object sf111;
+        static Object sf112;
+        static Object sf113;
+        static Object sf114;
+        static Object sf115;
+        static Object sf116;
+        static Object sf117;
+        static Object sf118;
+        static Object sf119;
+        static Object sf120;
+        static Object sf121;
+        static Object sf122;
+        static Object sf123;
+        static Object sf124;
+        static Object sf125;
+        static Object sf126;
+        static Object sf127;
+        static Object sf128;
+        static Object sf129;
+        static Object sf130;
+        static Object sf131;
+        static Object sf132;
+        static Object sf133;
+        static Object sf134;
+        static Object sf135;
+        static Object sf136;
+        static Object sf137;
+        static Object sf138;
+        static Object sf139;
+        static Object sf140;
+        static Object sf141;
+        static Object sf142;
+        static Object sf143;
+        static Object sf144;
+        static Object sf145;
+        static Object sf146;
+        static Object sf147;
+        static Object sf148;
+        static Object sf149;
+        static Object sf150;
+        static Object sf151;
+        static Object sf152;
+        static Object sf153;
+        static Object sf154;
+        static Object sf155;
+        static Object sf156;
+        static Object sf157;
+        static Object sf158;
+        static Object sf159;
+        static Object sf160;
+        static Object sf161;
+        static Object sf162;
+        static Object sf163;
+        static Object sf164;
+        static Object sf165;
+        static Object sf166;
+        static Object sf167;
+        static Object sf168;
+        static Object sf169;
+        static Object sf170;
+        static Object sf171;
+        static Object sf172;
+        static Object sf173;
+        static Object sf174;
+        static Object sf175;
+        static Object sf176;
+        static Object sf177;
+        static Object sf178;
+        static Object sf179;
+        static Object sf180;
+        static Object sf181;
+        static Object sf182;
+        static Object sf183;
+        static Object sf184;
+        static Object sf185;
+        static Object sf186;
+        static Object sf187;
+        static Object sf188;
+        static Object sf189;
+        static Object sf190;
+        static Object sf191;
+        static Object sf192;
+        static Object sf193;
+        static Object sf194;
+        static Object sf195;
+        static Object sf196;
+        static Object sf197;
+        static Object sf198;
+        static Object sf199;
+        static Object sf200;
+        static Object sf201;
+        static Object sf202;
+        static Object sf203;
+        static Object sf204;
+        static Object sf205;
+        static Object sf206;
+        static Object sf207;
+        static Object sf208;
+        static Object sf209;
+        static Object sf210;
+        static Object sf211;
+        static Object sf212;
+        static Object sf213;
+        static Object sf214;
+        static Object sf215;
+        static Object sf216;
+        static Object sf217;
+        static Object sf218;
+        static Object sf219;
+        static Object sf220;
+        static Object sf221;
+        static Object sf222;
+        static Object sf223;
+        static Object sf224;
+        static Object sf225;
+        static Object sf226;
+        static Object sf227;
+        static Object sf228;
+        static Object sf229;
+        static Object sf230;
+        static Object sf231;
+        static Object sf232;
+        static Object sf233;
+        static Object sf234;
+        static Object sf235;
+        static Object sf236;
+        static Object sf237;
+        static Object sf238;
+        static Object sf239;
+        static Object sf240;
+        static Object sf241;
+        static Object sf242;
+        static Object sf243;
+        static Object sf244;
+        static Object sf245;
+        static Object sf246;
+        static Object sf247;
+        static Object sf248;
+        static Object sf249;
+        static Object sf250;
+        static Object sf251;
+        static Object sf252;
+        static Object sf253;
+        static Object sf254;
+        static Object sf255;
+        static Object sf256;
+        static Object sf257;
+        static Object sf258;
+        static Object sf259;
+        static Object sf260;
+        static Object sf261;
+        static Object sf262;
+        static Object sf263;
+        static Object sf264;
+        static Object sf265;
+        static Object sf266;
+        static Object sf267;
+        static Object sf268;
+        static Object sf269;
+        static Object sf270;
+        static Object sf271;
+        static Object sf272;
+        static Object sf273;
+        static Object sf274;
+        static Object sf275;
+        static Object sf276;
+        static Object sf277;
+        static Object sf278;
+        static Object sf279;
+        static Object sf280;
+        static Object sf281;
+        static Object sf282;
+        static Object sf283;
+        static Object sf284;
+        static Object sf285;
+        static Object sf286;
+        static Object sf287;
+        static Object sf288;
+        static Object sf289;
+        static Object sf290;
+        static Object sf291;
+        static Object sf292;
+        static Object sf293;
+        static Object sf294;
+        static Object sf295;
+        static Object sf296;
+        static Object sf297;
+        static Object sf298;
+        static Object sf299;
+        static Object sf300;
+        static Object sf301;
+        static Object sf302;
+        static Object sf303;
+        static Object sf304;
+        static Object sf305;
+        static Object sf306;
+        static Object sf307;
+        static Object sf308;
+        static Object sf309;
+        static Object sf310;
+        static Object sf311;
+        static Object sf312;
+        static Object sf313;
+        static Object sf314;
+        static Object sf315;
+        static Object sf316;
+        static Object sf317;
+        static Object sf318;
+        static Object sf319;
+        static Object sf320;
+        static Object sf321;
+        static Object sf322;
+        static Object sf323;
+        static Object sf324;
+        static Object sf325;
+        static Object sf326;
+        static Object sf327;
+        static Object sf328;
+        static Object sf329;
+        static Object sf330;
+        static Object sf331;
+        static Object sf332;
+        static Object sf333;
+        static Object sf334;
+        static Object sf335;
+        static Object sf336;
+        static Object sf337;
+        static Object sf338;
+        static Object sf339;
+        static Object sf340;
+        static Object sf341;
+        static Object sf342;
+        static Object sf343;
+        static Object sf344;
+        static Object sf345;
+        static Object sf346;
+        static Object sf347;
+        static Object sf348;
+        static Object sf349;
+        static Object sf350;
+        static Object sf351;
+        static Object sf352;
+        static Object sf353;
+        static Object sf354;
+        static Object sf355;
+        static Object sf356;
+        static Object sf357;
+        static Object sf358;
+        static Object sf359;
+        static Object sf360;
+        static Object sf361;
+        static Object sf362;
+        static Object sf363;
+        static Object sf364;
+        static Object sf365;
+        static Object sf366;
+        static Object sf367;
+        static Object sf368;
+        static Object sf369;
+        static Object sf370;
+        static Object sf371;
+        static Object sf372;
+        static Object sf373;
+        static Object sf374;
+        static Object sf375;
+        static Object sf376;
+        static Object sf377;
+        static Object sf378;
+        static Object sf379;
+        static Object sf380;
+        static Object sf381;
+        static Object sf382;
+        static Object sf383;
+        static Object sf384;
+        static Object sf385;
+        static Object sf386;
+        static Object sf387;
+        static Object sf388;
+        static Object sf389;
+        static Object sf390;
+        static Object sf391;
+        static Object sf392;
+        static Object sf393;
+        static Object sf394;
+        static Object sf395;
+        static Object sf396;
+        static Object sf397;
+        static Object sf398;
+        static Object sf399;
+        static Object sf400;
+        static Object sf401;
+        static Object sf402;
+        static Object sf403;
+        static Object sf404;
+        static Object sf405;
+        static Object sf406;
+        static Object sf407;
+        static Object sf408;
+        static Object sf409;
+        static Object sf410;
+        static Object sf411;
+        static Object sf412;
+        static Object sf413;
+        static Object sf414;
+        static Object sf415;
+        static Object sf416;
+        static Object sf417;
+        static Object sf418;
+        static Object sf419;
+        static Object sf420;
+        static Object sf421;
+        static Object sf422;
+        static Object sf423;
+        static Object sf424;
+        static Object sf425;
+        static Object sf426;
+        static Object sf427;
+        static Object sf428;
+        static Object sf429;
+        static Object sf430;
+        static Object sf431;
+        static Object sf432;
+        static Object sf433;
+        static Object sf434;
+        static Object sf435;
+        static Object sf436;
+        static Object sf437;
+        static Object sf438;
+        static Object sf439;
+        static Object sf440;
+        static Object sf441;
+        static Object sf442;
+        static Object sf443;
+        static Object sf444;
+        static Object sf445;
+        static Object sf446;
+        static Object sf447;
+        static Object sf448;
+        static Object sf449;
+        static Object sf450;
+        static Object sf451;
+        static Object sf452;
+        static Object sf453;
+        static Object sf454;
+        static Object sf455;
+        static Object sf456;
+        static Object sf457;
+        static Object sf458;
+        static Object sf459;
+        static Object sf460;
+        static Object sf461;
+        static Object sf462;
+        static Object sf463;
+        static Object sf464;
+        static Object sf465;
+        static Object sf466;
+        static Object sf467;
+        static Object sf468;
+        static Object sf469;
+        static Object sf470;
+        static Object sf471;
+        static Object sf472;
+        static Object sf473;
+        static Object sf474;
+        static Object sf475;
+        static Object sf476;
+        static Object sf477;
+        static Object sf478;
+        static Object sf479;
+        static Object sf480;
+        static Object sf481;
+        static Object sf482;
+        static Object sf483;
+        static Object sf484;
+        static Object sf485;
+        static Object sf486;
+        static Object sf487;
+        static Object sf488;
+        static Object sf489;
+        static Object sf490;
+        static Object sf491;
+        static Object sf492;
+        static Object sf493;
+        static Object sf494;
+        static Object sf495;
+        static Object sf496;
+        static Object sf497;
+        static Object sf498;
+        static Object sf499;
+        static Object sf500;
+        static Object sf501;
+        static Object sf502;
+        static Object sf503;
+        static Object sf504;
+        static Object sf505;
+        static Object sf506;
+        static Object sf507;
+        static Object sf508;
+        static Object sf509;
+        static Object sf510;
+        static Object sf511;
+        static Object sf512;
+        static Object sf513;
+        static Object sf514;
+        static Object sf515;
+        static Object sf516;
+        static Object sf517;
+        static Object sf518;
+        static Object sf519;
+        static Object sf520;
+        static Object sf521;
+        static Object sf522;
+        static Object sf523;
+        static Object sf524;
+        static Object sf525;
+        static Object sf526;
+        static Object sf527;
+        static Object sf528;
+        static Object sf529;
+        static Object sf530;
+        static Object sf531;
+        static Object sf532;
+        static Object sf533;
+        static Object sf534;
+        static Object sf535;
+        static Object sf536;
+        static Object sf537;
+        static Object sf538;
+        static Object sf539;
+        static Object sf540;
+        static Object sf541;
+        static Object sf542;
+        static Object sf543;
+        static Object sf544;
+        static Object sf545;
+        static Object sf546;
+        static Object sf547;
+        static Object sf548;
+        static Object sf549;
+        static Object sf550;
+        static Object sf551;
+        static Object sf552;
+        static Object sf553;
+        static Object sf554;
+        static Object sf555;
+        static Object sf556;
+        static Object sf557;
+        static Object sf558;
+        static Object sf559;
+        static Object sf560;
+        static Object sf561;
+        static Object sf562;
+        static Object sf563;
+        static Object sf564;
+        static Object sf565;
+        static Object sf566;
+        static Object sf567;
+        static Object sf568;
+        static Object sf569;
+        static Object sf570;
+        static Object sf571;
+        static Object sf572;
+        static Object sf573;
+        static Object sf574;
+        static Object sf575;
+        static Object sf576;
+        static Object sf577;
+        static Object sf578;
+        static Object sf579;
+        static Object sf580;
+        static Object sf581;
+        static Object sf582;
+        static Object sf583;
+        static Object sf584;
+        static Object sf585;
+        static Object sf586;
+        static Object sf587;
+        static Object sf588;
+        static Object sf589;
+        static Object sf590;
+        static Object sf591;
+        static Object sf592;
+        static Object sf593;
+        static Object sf594;
+        static Object sf595;
+        static Object sf596;
+        static Object sf597;
+        static Object sf598;
+        static Object sf599;
+        static Object sf600;
+        static Object sf601;
+        static Object sf602;
+        static Object sf603;
+        static Object sf604;
+        static Object sf605;
+        static Object sf606;
+        static Object sf607;
+        static Object sf608;
+        static Object sf609;
+        static Object sf610;
+        static Object sf611;
+        static Object sf612;
+        static Object sf613;
+        static Object sf614;
+        static Object sf615;
+        static Object sf616;
+        static Object sf617;
+        static Object sf618;
+        static Object sf619;
+        static Object sf620;
+        static Object sf621;
+        static Object sf622;
+        static Object sf623;
+        static Object sf624;
+        static Object sf625;
+        static Object sf626;
+        static Object sf627;
+        static Object sf628;
+        static Object sf629;
+        static Object sf630;
+        static Object sf631;
+        static Object sf632;
+        static Object sf633;
+        static Object sf634;
+        static Object sf635;
+        static Object sf636;
+        static Object sf637;
+        static Object sf638;
+        static Object sf639;
+        static Object sf640;
+        static Object sf641;
+        static Object sf642;
+        static Object sf643;
+        static Object sf644;
+        static Object sf645;
+        static Object sf646;
+        static Object sf647;
+        static Object sf648;
+        static Object sf649;
+        static Object sf650;
+        static Object sf651;
+        static Object sf652;
+        static Object sf653;
+        static Object sf654;
+        static Object sf655;
+        static Object sf656;
+        static Object sf657;
+        static Object sf658;
+        static Object sf659;
+        static Object sf660;
+        static Object sf661;
+        static Object sf662;
+        static Object sf663;
+        static Object sf664;
+        static Object sf665;
+        static Object sf666;
+        static Object sf667;
+        static Object sf668;
+        static Object sf669;
+        static Object sf670;
+        static Object sf671;
+        static Object sf672;
+        static Object sf673;
+        static Object sf674;
+        static Object sf675;
+        static Object sf676;
+        static Object sf677;
+        static Object sf678;
+        static Object sf679;
+        static Object sf680;
+        static Object sf681;
+        static Object sf682;
+        static Object sf683;
+        static Object sf684;
+        static Object sf685;
+        static Object sf686;
+        static Object sf687;
+        static Object sf688;
+        static Object sf689;
+        static Object sf690;
+        static Object sf691;
+        static Object sf692;
+        static Object sf693;
+        static Object sf694;
+        static Object sf695;
+        static Object sf696;
+        static Object sf697;
+        static Object sf698;
+        static Object sf699;
+        static Object sf700;
+        static Object sf701;
+        static Object sf702;
+        static Object sf703;
+        static Object sf704;
+        static Object sf705;
+        static Object sf706;
+        static Object sf707;
+        static Object sf708;
+        static Object sf709;
+        static Object sf710;
+        static Object sf711;
+        static Object sf712;
+        static Object sf713;
+        static Object sf714;
+        static Object sf715;
+        static Object sf716;
+        static Object sf717;
+        static Object sf718;
+        static Object sf719;
+        static Object sf720;
+        static Object sf721;
+        static Object sf722;
+        static Object sf723;
+        static Object sf724;
+        static Object sf725;
+        static Object sf726;
+        static Object sf727;
+        static Object sf728;
+        static Object sf729;
+        static Object sf730;
+        static Object sf731;
+        static Object sf732;
+        static Object sf733;
+        static Object sf734;
+        static Object sf735;
+        static Object sf736;
+        static Object sf737;
+        static Object sf738;
+        static Object sf739;
+        static Object sf740;
+        static Object sf741;
+        static Object sf742;
+        static Object sf743;
+        static Object sf744;
+        static Object sf745;
+        static Object sf746;
+        static Object sf747;
+        static Object sf748;
+        static Object sf749;
+        static Object sf750;
+        static Object sf751;
+        static Object sf752;
+        static Object sf753;
+        static Object sf754;
+        static Object sf755;
+        static Object sf756;
+        static Object sf757;
+        static Object sf758;
+        static Object sf759;
+        static Object sf760;
+        static Object sf761;
+        static Object sf762;
+        static Object sf763;
+        static Object sf764;
+        static Object sf765;
+        static Object sf766;
+        static Object sf767;
+        static Object sf768;
+        static Object sf769;
+        static Object sf770;
+        static Object sf771;
+        static Object sf772;
+        static Object sf773;
+        static Object sf774;
+        static Object sf775;
+        static Object sf776;
+        static Object sf777;
+        static Object sf778;
+        static Object sf779;
+        static Object sf780;
+        static Object sf781;
+        static Object sf782;
+        static Object sf783;
+        static Object sf784;
+        static Object sf785;
+        static Object sf786;
+        static Object sf787;
+        static Object sf788;
+        static Object sf789;
+        static Object sf790;
+        static Object sf791;
+        static Object sf792;
+        static Object sf793;
+        static Object sf794;
+        static Object sf795;
+        static Object sf796;
+        static Object sf797;
+        static Object sf798;
+        static Object sf799;
+        static Object sf800;
+        static Object sf801;
+        static Object sf802;
+        static Object sf803;
+        static Object sf804;
+        static Object sf805;
+        static Object sf806;
+        static Object sf807;
+        static Object sf808;
+        static Object sf809;
+        static Object sf810;
+        static Object sf811;
+        static Object sf812;
+        static Object sf813;
+        static Object sf814;
+        static Object sf815;
+        static Object sf816;
+        static Object sf817;
+        static Object sf818;
+        static Object sf819;
+        static Object sf820;
+        static Object sf821;
+        static Object sf822;
+        static Object sf823;
+        static Object sf824;
+        static Object sf825;
+        static Object sf826;
+        static Object sf827;
+        static Object sf828;
+        static Object sf829;
+        static Object sf830;
+        static Object sf831;
+        static Object sf832;
+        static Object sf833;
+        static Object sf834;
+        static Object sf835;
+        static Object sf836;
+        static Object sf837;
+        static Object sf838;
+        static Object sf839;
+        static Object sf840;
+        static Object sf841;
+        static Object sf842;
+        static Object sf843;
+        static Object sf844;
+        static Object sf845;
+        static Object sf846;
+        static Object sf847;
+        static Object sf848;
+        static Object sf849;
+        static Object sf850;
+        static Object sf851;
+        static Object sf852;
+        static Object sf853;
+        static Object sf854;
+        static Object sf855;
+        static Object sf856;
+        static Object sf857;
+        static Object sf858;
+        static Object sf859;
+        static Object sf860;
+        static Object sf861;
+        static Object sf862;
+        static Object sf863;
+        static Object sf864;
+        static Object sf865;
+        static Object sf866;
+        static Object sf867;
+        static Object sf868;
+        static Object sf869;
+        static Object sf870;
+        static Object sf871;
+        static Object sf872;
+        static Object sf873;
+        static Object sf874;
+        static Object sf875;
+        static Object sf876;
+        static Object sf877;
+        static Object sf878;
+        static Object sf879;
+        static Object sf880;
+        static Object sf881;
+        static Object sf882;
+        static Object sf883;
+        static Object sf884;
+        static Object sf885;
+        static Object sf886;
+        static Object sf887;
+        static Object sf888;
+        static Object sf889;
+        static Object sf890;
+        static Object sf891;
+        static Object sf892;
+        static Object sf893;
+        static Object sf894;
+        static Object sf895;
+        static Object sf896;
+        static Object sf897;
+        static Object sf898;
+        static Object sf899;
+        static Object sf900;
+        static Object sf901;
+        static Object sf902;
+        static Object sf903;
+        static Object sf904;
+        static Object sf905;
+        static Object sf906;
+        static Object sf907;
+        static Object sf908;
+        static Object sf909;
+        static Object sf910;
+        static Object sf911;
+        static Object sf912;
+        static Object sf913;
+        static Object sf914;
+        static Object sf915;
+        static Object sf916;
+        static Object sf917;
+        static Object sf918;
+        static Object sf919;
+        static Object sf920;
+        static Object sf921;
+        static Object sf922;
+        static Object sf923;
+        static Object sf924;
+        static Object sf925;
+        static Object sf926;
+        static Object sf927;
+        static Object sf928;
+        static Object sf929;
+        static Object sf930;
+        static Object sf931;
+        static Object sf932;
+        static Object sf933;
+        static Object sf934;
+        static Object sf935;
+        static Object sf936;
+        static Object sf937;
+        static Object sf938;
+        static Object sf939;
+        static Object sf940;
+        static Object sf941;
+        static Object sf942;
+        static Object sf943;
+        static Object sf944;
+        static Object sf945;
+        static Object sf946;
+        static Object sf947;
+        static Object sf948;
+        static Object sf949;
+        static Object sf950;
+        static Object sf951;
+        static Object sf952;
+        static Object sf953;
+        static Object sf954;
+        static Object sf955;
+        static Object sf956;
+        static Object sf957;
+        static Object sf958;
+        static Object sf959;
+        static Object sf960;
+        static Object sf961;
+        static Object sf962;
+        static Object sf963;
+        static Object sf964;
+        static Object sf965;
+        static Object sf966;
+        static Object sf967;
+        static Object sf968;
+        static Object sf969;
+        static Object sf970;
+        static Object sf971;
+        static Object sf972;
+        static Object sf973;
+        static Object sf974;
+        static Object sf975;
+        static Object sf976;
+        static Object sf977;
+        static Object sf978;
+        static Object sf979;
+        static Object sf980;
+        static Object sf981;
+        static Object sf982;
+        static Object sf983;
+        static Object sf984;
+        static Object sf985;
+        static Object sf986;
+        static Object sf987;
+        static Object sf988;
+        static Object sf989;
+        static Object sf990;
+        static Object sf991;
+        static Object sf992;
+        static Object sf993;
+        static Object sf994;
+        static Object sf995;
+        static Object sf996;
+        static Object sf997;
+        static Object sf998;
+        static Object sf999;
+        static Object sf1000;
+        static Object sf1001;
+        static Object sf1002;
+        static Object sf1003;
+        static Object sf1004;
+        static Object sf1005;
+        static Object sf1006;
+        static Object sf1007;
+        static Object sf1008;
+        static Object sf1009;
+        static Object sf1010;
+        static Object sf1011;
+        static Object sf1012;
+        static Object sf1013;
+        static Object sf1014;
+        static Object sf1015;
+        static Object sf1016;
+        static Object sf1017;
+        static Object sf1018;
+        static Object sf1019;
+        static Object sf1020;
+        static Object sf1021;
+        static Object sf1022;
+        static Object sf1023;
+        static Object sf1024;
+        static Object sf1025;
+        static Object sf1026;
+        static Object sf1027;
+        static Object sf1028;
+        static Object sf1029;
+        static Object sf1030;
+        static Object sf1031;
+        static Object sf1032;
+        static Object sf1033;
+        static Object sf1034;
+        static Object sf1035;
+        static Object sf1036;
+        static Object sf1037;
+        static Object sf1038;
+        static Object sf1039;
+        static Object sf1040;
+        static Object sf1041;
+        static Object sf1042;
+        static Object sf1043;
+        static Object sf1044;
+        static Object sf1045;
+        static Object sf1046;
+        static Object sf1047;
+        static Object sf1048;
+        static Object sf1049;
+        static Object sf1050;
+        static Object sf1051;
+        static Object sf1052;
+        static Object sf1053;
+        static Object sf1054;
+        static Object sf1055;
+        static Object sf1056;
+        static Object sf1057;
+        static Object sf1058;
+        static Object sf1059;
+        static Object sf1060;
+        static Object sf1061;
+        static Object sf1062;
+        static Object sf1063;
+        static Object sf1064;
+        static Object sf1065;
+        static Object sf1066;
+        static Object sf1067;
+        static Object sf1068;
+        static Object sf1069;
+        static Object sf1070;
+        static Object sf1071;
+        static Object sf1072;
+        static Object sf1073;
+        static Object sf1074;
+        static Object sf1075;
+        static Object sf1076;
+        static Object sf1077;
+        static Object sf1078;
+        static Object sf1079;
+        static Object sf1080;
+        static Object sf1081;
+        static Object sf1082;
+        static Object sf1083;
+        static Object sf1084;
+        static Object sf1085;
+        static Object sf1086;
+        static Object sf1087;
+        static Object sf1088;
+        static Object sf1089;
+        static Object sf1090;
+        static Object sf1091;
+        static Object sf1092;
+        static Object sf1093;
+        static Object sf1094;
+        static Object sf1095;
+        static Object sf1096;
+        static Object sf1097;
+        static Object sf1098;
+        static Object sf1099;
+        static Object sf1100;
+        static Object sf1101;
+        static Object sf1102;
+        static Object sf1103;
+        static Object sf1104;
+        static Object sf1105;
+        static Object sf1106;
+        static Object sf1107;
+        static Object sf1108;
+        static Object sf1109;
+        static Object sf1110;
+        static Object sf1111;
+        static Object sf1112;
+        static Object sf1113;
+        static Object sf1114;
+        static Object sf1115;
+        static Object sf1116;
+        static Object sf1117;
+        static Object sf1118;
+        static Object sf1119;
+        static Object sf1120;
+        static Object sf1121;
+        static Object sf1122;
+        static Object sf1123;
+        static Object sf1124;
+        static Object sf1125;
+        static Object sf1126;
+        static Object sf1127;
+        static Object sf1128;
+        static Object sf1129;
+        static Object sf1130;
+        static Object sf1131;
+        static Object sf1132;
+        static Object sf1133;
+        static Object sf1134;
+        static Object sf1135;
+        static Object sf1136;
+        static Object sf1137;
+        static Object sf1138;
+        static Object sf1139;
+        static Object sf1140;
+        static Object sf1141;
+        static Object sf1142;
+        static Object sf1143;
+        static Object sf1144;
+        static Object sf1145;
+        static Object sf1146;
+        static Object sf1147;
+        static Object sf1148;
+        static Object sf1149;
+        static Object sf1150;
+        static Object sf1151;
+        static Object sf1152;
+        static Object sf1153;
+        static Object sf1154;
+        static Object sf1155;
+        static Object sf1156;
+        static Object sf1157;
+        static Object sf1158;
+        static Object sf1159;
+        static Object sf1160;
+        static Object sf1161;
+        static Object sf1162;
+        static Object sf1163;
+        static Object sf1164;
+        static Object sf1165;
+        static Object sf1166;
+        static Object sf1167;
+        static Object sf1168;
+        static Object sf1169;
+        static Object sf1170;
+        static Object sf1171;
+        static Object sf1172;
+        static Object sf1173;
+        static Object sf1174;
+        static Object sf1175;
+        static Object sf1176;
+        static Object sf1177;
+        static Object sf1178;
+        static Object sf1179;
+        static Object sf1180;
+        static Object sf1181;
+        static Object sf1182;
+        static Object sf1183;
+        static Object sf1184;
+        static Object sf1185;
+        static Object sf1186;
+        static Object sf1187;
+        static Object sf1188;
+        static Object sf1189;
+        static Object sf1190;
+        static Object sf1191;
+        static Object sf1192;
+        static Object sf1193;
+        static Object sf1194;
+        static Object sf1195;
+        static Object sf1196;
+        static Object sf1197;
+        static Object sf1198;
+        static Object sf1199;
+        static Object sf1200;
+        static Object sf1201;
+        static Object sf1202;
+        static Object sf1203;
+        static Object sf1204;
+        static Object sf1205;
+        static Object sf1206;
+        static Object sf1207;
+        static Object sf1208;
+        static Object sf1209;
+        static Object sf1210;
+        static Object sf1211;
+        static Object sf1212;
+        static Object sf1213;
+        static Object sf1214;
+        static Object sf1215;
+        static Object sf1216;
+        static Object sf1217;
+        static Object sf1218;
+        static Object sf1219;
+        static Object sf1220;
+        static Object sf1221;
+        static Object sf1222;
+        static Object sf1223;
+        static Object sf1224;
+        static Object sf1225;
+        static Object sf1226;
+        static Object sf1227;
+        static Object sf1228;
+        static Object sf1229;
+        static Object sf1230;
+        static Object sf1231;
+        static Object sf1232;
+        static Object sf1233;
+        static Object sf1234;
+        static Object sf1235;
+        static Object sf1236;
+        static Object sf1237;
+        static Object sf1238;
+        static Object sf1239;
+        static Object sf1240;
+        static Object sf1241;
+        static Object sf1242;
+        static Object sf1243;
+        static Object sf1244;
+        static Object sf1245;
+        static Object sf1246;
+        static Object sf1247;
+        static Object sf1248;
+        static Object sf1249;
+        static Object sf1250;
+        static Object sf1251;
+        static Object sf1252;
+        static Object sf1253;
+        static Object sf1254;
+        static Object sf1255;
+        static Object sf1256;
+        static Object sf1257;
+        static Object sf1258;
+        static Object sf1259;
+        static Object sf1260;
+        static Object sf1261;
+        static Object sf1262;
+        static Object sf1263;
+        static Object sf1264;
+        static Object sf1265;
+        static Object sf1266;
+        static Object sf1267;
+        static Object sf1268;
+        static Object sf1269;
+        static Object sf1270;
+        static Object sf1271;
+        static Object sf1272;
+        static Object sf1273;
+        static Object sf1274;
+        static Object sf1275;
+        static Object sf1276;
+        static Object sf1277;
+        static Object sf1278;
+        static Object sf1279;
+        static Object sf1280;
+        static Object sf1281;
+        static Object sf1282;
+        static Object sf1283;
+        static Object sf1284;
+        static Object sf1285;
+        static Object sf1286;
+        static Object sf1287;
+        static Object sf1288;
+        static Object sf1289;
+        static Object sf1290;
+        static Object sf1291;
+        static Object sf1292;
+        static Object sf1293;
+        static Object sf1294;
+        static Object sf1295;
+        static Object sf1296;
+        static Object sf1297;
+        static Object sf1298;
+        static Object sf1299;
+        static Object sf1300;
+        static Object sf1301;
+        static Object sf1302;
+        static Object sf1303;
+        static Object sf1304;
+        static Object sf1305;
+        static Object sf1306;
+        static Object sf1307;
+        static Object sf1308;
+        static Object sf1309;
+        static Object sf1310;
+        static Object sf1311;
+        static Object sf1312;
+        static Object sf1313;
+        static Object sf1314;
+        static Object sf1315;
+        static Object sf1316;
+        static Object sf1317;
+        static Object sf1318;
+        static Object sf1319;
+        static Object sf1320;
+        static Object sf1321;
+        static Object sf1322;
+        static Object sf1323;
+        static Object sf1324;
+        static Object sf1325;
+        static Object sf1326;
+        static Object sf1327;
+        static Object sf1328;
+        static Object sf1329;
+        static Object sf1330;
+        static Object sf1331;
+        static Object sf1332;
+        static Object sf1333;
+        static Object sf1334;
+        static Object sf1335;
+        static Object sf1336;
+        static Object sf1337;
+        static Object sf1338;
+        static Object sf1339;
+        static Object sf1340;
+        static Object sf1341;
+        static Object sf1342;
+        static Object sf1343;
+        static Object sf1344;
+        static Object sf1345;
+        static Object sf1346;
+        static Object sf1347;
+        static Object sf1348;
+        static Object sf1349;
+        static Object sf1350;
+        static Object sf1351;
+        static Object sf1352;
+        static Object sf1353;
+        static Object sf1354;
+        static Object sf1355;
+        static Object sf1356;
+        static Object sf1357;
+        static Object sf1358;
+        static Object sf1359;
+        static Object sf1360;
+        static Object sf1361;
+        static Object sf1362;
+        static Object sf1363;
+        static Object sf1364;
+        static Object sf1365;
+        static Object sf1366;
+        static Object sf1367;
+        static Object sf1368;
+        static Object sf1369;
+        static Object sf1370;
+        static Object sf1371;
+        static Object sf1372;
+        static Object sf1373;
+        static Object sf1374;
+        static Object sf1375;
+        static Object sf1376;
+        static Object sf1377;
+        static Object sf1378;
+        static Object sf1379;
+        static Object sf1380;
+        static Object sf1381;
+        static Object sf1382;
+        static Object sf1383;
+        static Object sf1384;
+        static Object sf1385;
+        static Object sf1386;
+        static Object sf1387;
+        static Object sf1388;
+        static Object sf1389;
+        static Object sf1390;
+        static Object sf1391;
+        static Object sf1392;
+        static Object sf1393;
+        static Object sf1394;
+        static Object sf1395;
+        static Object sf1396;
+        static Object sf1397;
+        static Object sf1398;
+        static Object sf1399;
+        static Object sf1400;
+        static Object sf1401;
+        static Object sf1402;
+        static Object sf1403;
+        static Object sf1404;
+        static Object sf1405;
+        static Object sf1406;
+        static Object sf1407;
+        static Object sf1408;
+        static Object sf1409;
+        static Object sf1410;
+        static Object sf1411;
+        static Object sf1412;
+        static Object sf1413;
+        static Object sf1414;
+        static Object sf1415;
+        static Object sf1416;
+        static Object sf1417;
+        static Object sf1418;
+        static Object sf1419;
+        static Object sf1420;
+        static Object sf1421;
+        static Object sf1422;
+        static Object sf1423;
+        static Object sf1424;
+        static Object sf1425;
+        static Object sf1426;
+        static Object sf1427;
+        static Object sf1428;
+        static Object sf1429;
+        static Object sf1430;
+        static Object sf1431;
+        static Object sf1432;
+        static Object sf1433;
+        static Object sf1434;
+        static Object sf1435;
+        static Object sf1436;
+        static Object sf1437;
+        static Object sf1438;
+        static Object sf1439;
+        static Object sf1440;
+        static Object sf1441;
+        static Object sf1442;
+        static Object sf1443;
+        static Object sf1444;
+        static Object sf1445;
+        static Object sf1446;
+        static Object sf1447;
+        static Object sf1448;
+        static Object sf1449;
+        static Object sf1450;
+        static Object sf1451;
+        static Object sf1452;
+        static Object sf1453;
+        static Object sf1454;
+        static Object sf1455;
+        static Object sf1456;
+        static Object sf1457;
+        static Object sf1458;
+        static Object sf1459;
+        static Object sf1460;
+        static Object sf1461;
+        static Object sf1462;
+        static Object sf1463;
+        static Object sf1464;
+        static Object sf1465;
+        static Object sf1466;
+        static Object sf1467;
+        static Object sf1468;
+        static Object sf1469;
+        static Object sf1470;
+        static Object sf1471;
+        static Object sf1472;
+        static Object sf1473;
+        static Object sf1474;
+        static Object sf1475;
+        static Object sf1476;
+        static Object sf1477;
+        static Object sf1478;
+        static Object sf1479;
+        static Object sf1480;
+        static Object sf1481;
+        static Object sf1482;
+        static Object sf1483;
+        static Object sf1484;
+        static Object sf1485;
+        static Object sf1486;
+        static Object sf1487;
+        static Object sf1488;
+        static Object sf1489;
+        static Object sf1490;
+        static Object sf1491;
+        static Object sf1492;
+        static Object sf1493;
+        static Object sf1494;
+        static Object sf1495;
+        static Object sf1496;
+        static Object sf1497;
+        static Object sf1498;
+        static Object sf1499;
+        static Object sf1500;
+        static Object sf1501;
+        static Object sf1502;
+        static Object sf1503;
+        static Object sf1504;
+        static Object sf1505;
+        static Object sf1506;
+        static Object sf1507;
+        static Object sf1508;
+        static Object sf1509;
+        static Object sf1510;
+        static Object sf1511;
+        static Object sf1512;
+        static Object sf1513;
+        static Object sf1514;
+        static Object sf1515;
+        static Object sf1516;
+        static Object sf1517;
+        static Object sf1518;
+        static Object sf1519;
+        static Object sf1520;
+        static Object sf1521;
+        static Object sf1522;
+        static Object sf1523;
+        static Object sf1524;
+        static Object sf1525;
+        static Object sf1526;
+        static Object sf1527;
+        static Object sf1528;
+        static Object sf1529;
+        static Object sf1530;
+        static Object sf1531;
+        static Object sf1532;
+        static Object sf1533;
+        static Object sf1534;
+        static Object sf1535;
+        static Object sf1536;
+        static Object sf1537;
+        static Object sf1538;
+        static Object sf1539;
+        static Object sf1540;
+        static Object sf1541;
+        static Object sf1542;
+        static Object sf1543;
+        static Object sf1544;
+        static Object sf1545;
+        static Object sf1546;
+        static Object sf1547;
+        static Object sf1548;
+        static Object sf1549;
+        static Object sf1550;
+        static Object sf1551;
+        static Object sf1552;
+        static Object sf1553;
+        static Object sf1554;
+        static Object sf1555;
+        static Object sf1556;
+        static Object sf1557;
+        static Object sf1558;
+        static Object sf1559;
+        static Object sf1560;
+        static Object sf1561;
+        static Object sf1562;
+        static Object sf1563;
+        static Object sf1564;
+        static Object sf1565;
+        static Object sf1566;
+        static Object sf1567;
+        static Object sf1568;
+        static Object sf1569;
+        static Object sf1570;
+        static Object sf1571;
+        static Object sf1572;
+        static Object sf1573;
+        static Object sf1574;
+        static Object sf1575;
+        static Object sf1576;
+        static Object sf1577;
+        static Object sf1578;
+        static Object sf1579;
+        static Object sf1580;
+        static Object sf1581;
+        static Object sf1582;
+        static Object sf1583;
+        static Object sf1584;
+        static Object sf1585;
+        static Object sf1586;
+        static Object sf1587;
+        static Object sf1588;
+        static Object sf1589;
+        static Object sf1590;
+        static Object sf1591;
+        static Object sf1592;
+        static Object sf1593;
+        static Object sf1594;
+        static Object sf1595;
+        static Object sf1596;
+        static Object sf1597;
+        static Object sf1598;
+        static Object sf1599;
+        static Object sf1600;
+        static Object sf1601;
+        static Object sf1602;
+        static Object sf1603;
+        static Object sf1604;
+        static Object sf1605;
+        static Object sf1606;
+        static Object sf1607;
+        static Object sf1608;
+        static Object sf1609;
+        static Object sf1610;
+        static Object sf1611;
+        static Object sf1612;
+        static Object sf1613;
+        static Object sf1614;
+        static Object sf1615;
+        static Object sf1616;
+        static Object sf1617;
+        static Object sf1618;
+        static Object sf1619;
+        static Object sf1620;
+        static Object sf1621;
+        static Object sf1622;
+        static Object sf1623;
+        static Object sf1624;
+        static Object sf1625;
+        static Object sf1626;
+        static Object sf1627;
+        static Object sf1628;
+        static Object sf1629;
+        static Object sf1630;
+        static Object sf1631;
+        static Object sf1632;
+        static Object sf1633;
+        static Object sf1634;
+        static Object sf1635;
+        static Object sf1636;
+        static Object sf1637;
+        static Object sf1638;
+        static Object sf1639;
+        static Object sf1640;
+        static Object sf1641;
+        static Object sf1642;
+        static Object sf1643;
+        static Object sf1644;
+        static Object sf1645;
+        static Object sf1646;
+        static Object sf1647;
+        static Object sf1648;
+        static Object sf1649;
+        static Object sf1650;
+        static Object sf1651;
+        static Object sf1652;
+        static Object sf1653;
+        static Object sf1654;
+        static Object sf1655;
+        static Object sf1656;
+        static Object sf1657;
+        static Object sf1658;
+        static Object sf1659;
+        static Object sf1660;
+        static Object sf1661;
+        static Object sf1662;
+        static Object sf1663;
+        static Object sf1664;
+        static Object sf1665;
+        static Object sf1666;
+        static Object sf1667;
+        static Object sf1668;
+        static Object sf1669;
+        static Object sf1670;
+        static Object sf1671;
+        static Object sf1672;
+        static Object sf1673;
+        static Object sf1674;
+        static Object sf1675;
+        static Object sf1676;
+        static Object sf1677;
+        static Object sf1678;
+        static Object sf1679;
+        static Object sf1680;
+        static Object sf1681;
+        static Object sf1682;
+        static Object sf1683;
+        static Object sf1684;
+        static Object sf1685;
+        static Object sf1686;
+        static Object sf1687;
+        static Object sf1688;
+        static Object sf1689;
+        static Object sf1690;
+        static Object sf1691;
+        static Object sf1692;
+        static Object sf1693;
+        static Object sf1694;
+        static Object sf1695;
+        static Object sf1696;
+        static Object sf1697;
+        static Object sf1698;
+        static Object sf1699;
+        static Object sf1700;
+        static Object sf1701;
+        static Object sf1702;
+        static Object sf1703;
+        static Object sf1704;
+        static Object sf1705;
+        static Object sf1706;
+        static Object sf1707;
+        static Object sf1708;
+        static Object sf1709;
+        static Object sf1710;
+        static Object sf1711;
+        static Object sf1712;
+        static Object sf1713;
+        static Object sf1714;
+        static Object sf1715;
+        static Object sf1716;
+        static Object sf1717;
+        static Object sf1718;
+        static Object sf1719;
+        static Object sf1720;
+        static Object sf1721;
+        static Object sf1722;
+        static Object sf1723;
+        static Object sf1724;
+        static Object sf1725;
+        static Object sf1726;
+        static Object sf1727;
+        static Object sf1728;
+        static Object sf1729;
+        static Object sf1730;
+        static Object sf1731;
+        static Object sf1732;
+        static Object sf1733;
+        static Object sf1734;
+        static Object sf1735;
+        static Object sf1736;
+        static Object sf1737;
+        static Object sf1738;
+        static Object sf1739;
+        static Object sf1740;
+        static Object sf1741;
+        static Object sf1742;
+        static Object sf1743;
+        static Object sf1744;
+        static Object sf1745;
+        static Object sf1746;
+        static Object sf1747;
+        static Object sf1748;
+        static Object sf1749;
+        static Object sf1750;
+        static Object sf1751;
+        static Object sf1752;
+        static Object sf1753;
+        static Object sf1754;
+        static Object sf1755;
+        static Object sf1756;
+        static Object sf1757;
+        static Object sf1758;
+        static Object sf1759;
+        static Object sf1760;
+        static Object sf1761;
+        static Object sf1762;
+        static Object sf1763;
+        static Object sf1764;
+        static Object sf1765;
+        static Object sf1766;
+        static Object sf1767;
+        static Object sf1768;
+        static Object sf1769;
+        static Object sf1770;
+        static Object sf1771;
+        static Object sf1772;
+        static Object sf1773;
+        static Object sf1774;
+        static Object sf1775;
+        static Object sf1776;
+        static Object sf1777;
+        static Object sf1778;
+        static Object sf1779;
+        static Object sf1780;
+        static Object sf1781;
+        static Object sf1782;
+        static Object sf1783;
+        static Object sf1784;
+        static Object sf1785;
+        static Object sf1786;
+        static Object sf1787;
+        static Object sf1788;
+        static Object sf1789;
+        static Object sf1790;
+        static Object sf1791;
+        static Object sf1792;
+        static Object sf1793;
+        static Object sf1794;
+        static Object sf1795;
+        static Object sf1796;
+        static Object sf1797;
+        static Object sf1798;
+        static Object sf1799;
+        static Object sf1800;
+        static Object sf1801;
+        static Object sf1802;
+        static Object sf1803;
+        static Object sf1804;
+        static Object sf1805;
+        static Object sf1806;
+        static Object sf1807;
+        static Object sf1808;
+        static Object sf1809;
+        static Object sf1810;
+        static Object sf1811;
+        static Object sf1812;
+        static Object sf1813;
+        static Object sf1814;
+        static Object sf1815;
+        static Object sf1816;
+        static Object sf1817;
+        static Object sf1818;
+        static Object sf1819;
+        static Object sf1820;
+        static Object sf1821;
+        static Object sf1822;
+        static Object sf1823;
+        static Object sf1824;
+        static Object sf1825;
+        static Object sf1826;
+        static Object sf1827;
+        static Object sf1828;
+        static Object sf1829;
+        static Object sf1830;
+        static Object sf1831;
+        static Object sf1832;
+        static Object sf1833;
+        static Object sf1834;
+        static Object sf1835;
+        static Object sf1836;
+        static Object sf1837;
+        static Object sf1838;
+        static Object sf1839;
+        static Object sf1840;
+        static Object sf1841;
+        static Object sf1842;
+        static Object sf1843;
+        static Object sf1844;
+        static Object sf1845;
+        static Object sf1846;
+        static Object sf1847;
+        static Object sf1848;
+        static Object sf1849;
+        static Object sf1850;
+        static Object sf1851;
+        static Object sf1852;
+        static Object sf1853;
+        static Object sf1854;
+        static Object sf1855;
+        static Object sf1856;
+        static Object sf1857;
+        static Object sf1858;
+        static Object sf1859;
+        static Object sf1860;
+        static Object sf1861;
+        static Object sf1862;
+        static Object sf1863;
+        static Object sf1864;
+        static Object sf1865;
+        static Object sf1866;
+        static Object sf1867;
+        static Object sf1868;
+        static Object sf1869;
+        static Object sf1870;
+        static Object sf1871;
+        static Object sf1872;
+        static Object sf1873;
+        static Object sf1874;
+        static Object sf1875;
+        static Object sf1876;
+        static Object sf1877;
+        static Object sf1878;
+        static Object sf1879;
+        static Object sf1880;
+        static Object sf1881;
+        static Object sf1882;
+        static Object sf1883;
+        static Object sf1884;
+        static Object sf1885;
+        static Object sf1886;
+        static Object sf1887;
+        static Object sf1888;
+        static Object sf1889;
+        static Object sf1890;
+        static Object sf1891;
+        static Object sf1892;
+        static Object sf1893;
+        static Object sf1894;
+        static Object sf1895;
+        static Object sf1896;
+        static Object sf1897;
+        static Object sf1898;
+        static Object sf1899;
+        static Object sf1900;
+        static Object sf1901;
+        static Object sf1902;
+        static Object sf1903;
+        static Object sf1904;
+        static Object sf1905;
+        static Object sf1906;
+        static Object sf1907;
+        static Object sf1908;
+        static Object sf1909;
+        static Object sf1910;
+        static Object sf1911;
+        static Object sf1912;
+        static Object sf1913;
+        static Object sf1914;
+        static Object sf1915;
+        static Object sf1916;
+        static Object sf1917;
+        static Object sf1918;
+        static Object sf1919;
+        static Object sf1920;
+        static Object sf1921;
+        static Object sf1922;
+        static Object sf1923;
+        static Object sf1924;
+        static Object sf1925;
+        static Object sf1926;
+        static Object sf1927;
+        static Object sf1928;
+        static Object sf1929;
+        static Object sf1930;
+        static Object sf1931;
+        static Object sf1932;
+        static Object sf1933;
+        static Object sf1934;
+        static Object sf1935;
+        static Object sf1936;
+        static Object sf1937;
+        static Object sf1938;
+        static Object sf1939;
+        static Object sf1940;
+        static Object sf1941;
+        static Object sf1942;
+        static Object sf1943;
+        static Object sf1944;
+        static Object sf1945;
+        static Object sf1946;
+        static Object sf1947;
+        static Object sf1948;
+        static Object sf1949;
+        static Object sf1950;
+        static Object sf1951;
+        static Object sf1952;
+        static Object sf1953;
+        static Object sf1954;
+        static Object sf1955;
+        static Object sf1956;
+        static Object sf1957;
+        static Object sf1958;
+        static Object sf1959;
+        static Object sf1960;
+        static Object sf1961;
+        static Object sf1962;
+        static Object sf1963;
+        static Object sf1964;
+        static Object sf1965;
+        static Object sf1966;
+        static Object sf1967;
+        static Object sf1968;
+        static Object sf1969;
+        static Object sf1970;
+        static Object sf1971;
+        static Object sf1972;
+        static Object sf1973;
+        static Object sf1974;
+        static Object sf1975;
+        static Object sf1976;
+        static Object sf1977;
+        static Object sf1978;
+        static Object sf1979;
+        static Object sf1980;
+        static Object sf1981;
+        static Object sf1982;
+        static Object sf1983;
+        static Object sf1984;
+        static Object sf1985;
+        static Object sf1986;
+        static Object sf1987;
+        static Object sf1988;
+        static Object sf1989;
+        static Object sf1990;
+        static Object sf1991;
+        static Object sf1992;
+        static Object sf1993;
+        static Object sf1994;
+        static Object sf1995;
+        static Object sf1996;
+        static Object sf1997;
+        static Object sf1998;
+        static Object sf1999;
+        static Object sf2000;
+        static Object sf2001;
+        static Object sf2002;
+        static Object sf2003;
+        static Object sf2004;
+        static Object sf2005;
+        static Object sf2006;
+        static Object sf2007;
+        static Object sf2008;
+        static Object sf2009;
+        static Object sf2010;
+        static Object sf2011;
+        static Object sf2012;
+        static Object sf2013;
+        static Object sf2014;
+        static Object sf2015;
+        static Object sf2016;
+        static Object sf2017;
+        static Object sf2018;
+        static Object sf2019;
+        static Object sf2020;
+        static Object sf2021;
+        static Object sf2022;
+        static Object sf2023;
+        static Object sf2024;
+        static Object sf2025;
+        static Object sf2026;
+        static Object sf2027;
+        static Object sf2028;
+        static Object sf2029;
+        static Object sf2030;
+        static Object sf2031;
+        static Object sf2032;
+        static Object sf2033;
+        static Object sf2034;
+        static Object sf2035;
+        static Object sf2036;
+        static Object sf2037;
+        static Object sf2038;
+        static Object sf2039;
+        static Object sf2040;
+        static Object sf2041;
+        static Object sf2042;
+        static Object sf2043;
+        static Object sf2044;
+        static Object sf2045;
+        static Object sf2046;
+        static Object sf2047;
+        static Object sf2048;
+        static Object sf2049;
+        static Object sf2050;
+        static Object sf2051;
+        static Object sf2052;
+        static Object sf2053;
+        static Object sf2054;
+        static Object sf2055;
+        static Object sf2056;
+        static Object sf2057;
+        static Object sf2058;
+        static Object sf2059;
+        static Object sf2060;
+        static Object sf2061;
+        static Object sf2062;
+        static Object sf2063;
+        static Object sf2064;
+        static Object sf2065;
+        static Object sf2066;
+        static Object sf2067;
+        static Object sf2068;
+        static Object sf2069;
+        static Object sf2070;
+        static Object sf2071;
+        static Object sf2072;
+        static Object sf2073;
+        static Object sf2074;
+        static Object sf2075;
+        static Object sf2076;
+        static Object sf2077;
+        static Object sf2078;
+        static Object sf2079;
+        static Object sf2080;
+        static Object sf2081;
+        static Object sf2082;
+        static Object sf2083;
+        static Object sf2084;
+        static Object sf2085;
+        static Object sf2086;
+        static Object sf2087;
+        static Object sf2088;
+        static Object sf2089;
+        static Object sf2090;
+        static Object sf2091;
+        static Object sf2092;
+        static Object sf2093;
+        static Object sf2094;
+        static Object sf2095;
+        static Object sf2096;
+        static Object sf2097;
+        static Object sf2098;
+        static Object sf2099;
+        static Object sf2100;
+        static Object sf2101;
+        static Object sf2102;
+        static Object sf2103;
+        static Object sf2104;
+        static Object sf2105;
+        static Object sf2106;
+        static Object sf2107;
+        static Object sf2108;
+        static Object sf2109;
+        static Object sf2110;
+        static Object sf2111;
+        static Object sf2112;
+        static Object sf2113;
+        static Object sf2114;
+        static Object sf2115;
+        static Object sf2116;
+        static Object sf2117;
+        static Object sf2118;
+        static Object sf2119;
+        static Object sf2120;
+        static Object sf2121;
+        static Object sf2122;
+        static Object sf2123;
+        static Object sf2124;
+        static Object sf2125;
+        static Object sf2126;
+        static Object sf2127;
+        static Object sf2128;
+        static Object sf2129;
+        static Object sf2130;
+        static Object sf2131;
+        static Object sf2132;
+        static Object sf2133;
+        static Object sf2134;
+        static Object sf2135;
+        static Object sf2136;
+        static Object sf2137;
+        static Object sf2138;
+        static Object sf2139;
+        static Object sf2140;
+        static Object sf2141;
+        static Object sf2142;
+        static Object sf2143;
+        static Object sf2144;
+        static Object sf2145;
+        static Object sf2146;
+        static Object sf2147;
+        static Object sf2148;
+        static Object sf2149;
+        static Object sf2150;
+        static Object sf2151;
+        static Object sf2152;
+        static Object sf2153;
+        static Object sf2154;
+        static Object sf2155;
+        static Object sf2156;
+        static Object sf2157;
+        static Object sf2158;
+        static Object sf2159;
+        static Object sf2160;
+        static Object sf2161;
+        static Object sf2162;
+        static Object sf2163;
+        static Object sf2164;
+        static Object sf2165;
+        static Object sf2166;
+        static Object sf2167;
+        static Object sf2168;
+        static Object sf2169;
+        static Object sf2170;
+        static Object sf2171;
+        static Object sf2172;
+        static Object sf2173;
+        static Object sf2174;
+        static Object sf2175;
+        static Object sf2176;
+        static Object sf2177;
+        static Object sf2178;
+        static Object sf2179;
+        static Object sf2180;
+        static Object sf2181;
+        static Object sf2182;
+        static Object sf2183;
+        static Object sf2184;
+        static Object sf2185;
+        static Object sf2186;
+        static Object sf2187;
+        static Object sf2188;
+        static Object sf2189;
+        static Object sf2190;
+        static Object sf2191;
+        static Object sf2192;
+        static Object sf2193;
+        static Object sf2194;
+        static Object sf2195;
+        static Object sf2196;
+        static Object sf2197;
+        static Object sf2198;
+        static Object sf2199;
+        static Object sf2200;
+        static Object sf2201;
+        static Object sf2202;
+        static Object sf2203;
+        static Object sf2204;
+        static Object sf2205;
+        static Object sf2206;
+        static Object sf2207;
+        static Object sf2208;
+        static Object sf2209;
+        static Object sf2210;
+        static Object sf2211;
+        static Object sf2212;
+        static Object sf2213;
+        static Object sf2214;
+        static Object sf2215;
+        static Object sf2216;
+        static Object sf2217;
+        static Object sf2218;
+        static Object sf2219;
+        static Object sf2220;
+        static Object sf2221;
+        static Object sf2222;
+        static Object sf2223;
+        static Object sf2224;
+        static Object sf2225;
+        static Object sf2226;
+        static Object sf2227;
+        static Object sf2228;
+        static Object sf2229;
+        static Object sf2230;
+        static Object sf2231;
+        static Object sf2232;
+        static Object sf2233;
+        static Object sf2234;
+        static Object sf2235;
+        static Object sf2236;
+        static Object sf2237;
+        static Object sf2238;
+        static Object sf2239;
+        static Object sf2240;
+        static Object sf2241;
+        static Object sf2242;
+        static Object sf2243;
+        static Object sf2244;
+        static Object sf2245;
+        static Object sf2246;
+        static Object sf2247;
+        static Object sf2248;
+        static Object sf2249;
+        static Object sf2250;
+        static Object sf2251;
+        static Object sf2252;
+        static Object sf2253;
+        static Object sf2254;
+        static Object sf2255;
+        static Object sf2256;
+        static Object sf2257;
+        static Object sf2258;
+        static Object sf2259;
+        static Object sf2260;
+        static Object sf2261;
+        static Object sf2262;
+        static Object sf2263;
+        static Object sf2264;
+        static Object sf2265;
+        static Object sf2266;
+        static Object sf2267;
+        static Object sf2268;
+        static Object sf2269;
+        static Object sf2270;
+        static Object sf2271;
+        static Object sf2272;
+        static Object sf2273;
+        static Object sf2274;
+        static Object sf2275;
+        static Object sf2276;
+        static Object sf2277;
+        static Object sf2278;
+        static Object sf2279;
+        static Object sf2280;
+        static Object sf2281;
+        static Object sf2282;
+        static Object sf2283;
+        static Object sf2284;
+        static Object sf2285;
+        static Object sf2286;
+        static Object sf2287;
+        static Object sf2288;
+        static Object sf2289;
+        static Object sf2290;
+        static Object sf2291;
+        static Object sf2292;
+        static Object sf2293;
+        static Object sf2294;
+        static Object sf2295;
+        static Object sf2296;
+        static Object sf2297;
+        static Object sf2298;
+        static Object sf2299;
+        static Object sf2300;
+        static Object sf2301;
+        static Object sf2302;
+        static Object sf2303;
+        static Object sf2304;
+        static Object sf2305;
+        static Object sf2306;
+        static Object sf2307;
+        static Object sf2308;
+        static Object sf2309;
+        static Object sf2310;
+        static Object sf2311;
+        static Object sf2312;
+        static Object sf2313;
+        static Object sf2314;
+        static Object sf2315;
+        static Object sf2316;
+        static Object sf2317;
+        static Object sf2318;
+        static Object sf2319;
+        static Object sf2320;
+        static Object sf2321;
+        static Object sf2322;
+        static Object sf2323;
+        static Object sf2324;
+        static Object sf2325;
+        static Object sf2326;
+        static Object sf2327;
+        static Object sf2328;
+        static Object sf2329;
+        static Object sf2330;
+        static Object sf2331;
+        static Object sf2332;
+        static Object sf2333;
+        static Object sf2334;
+        static Object sf2335;
+        static Object sf2336;
+        static Object sf2337;
+        static Object sf2338;
+        static Object sf2339;
+        static Object sf2340;
+        static Object sf2341;
+        static Object sf2342;
+        static Object sf2343;
+        static Object sf2344;
+        static Object sf2345;
+        static Object sf2346;
+        static Object sf2347;
+        static Object sf2348;
+        static Object sf2349;
+        static Object sf2350;
+        static Object sf2351;
+        static Object sf2352;
+        static Object sf2353;
+        static Object sf2354;
+        static Object sf2355;
+        static Object sf2356;
+        static Object sf2357;
+        static Object sf2358;
+        static Object sf2359;
+        static Object sf2360;
+        static Object sf2361;
+        static Object sf2362;
+        static Object sf2363;
+        static Object sf2364;
+        static Object sf2365;
+        static Object sf2366;
+        static Object sf2367;
+        static Object sf2368;
+        static Object sf2369;
+        static Object sf2370;
+        static Object sf2371;
+        static Object sf2372;
+        static Object sf2373;
+        static Object sf2374;
+        static Object sf2375;
+        static Object sf2376;
+        static Object sf2377;
+        static Object sf2378;
+        static Object sf2379;
+        static Object sf2380;
+        static Object sf2381;
+        static Object sf2382;
+        static Object sf2383;
+        static Object sf2384;
+        static Object sf2385;
+        static Object sf2386;
+        static Object sf2387;
+        static Object sf2388;
+        static Object sf2389;
+        static Object sf2390;
+        static Object sf2391;
+        static Object sf2392;
+        static Object sf2393;
+        static Object sf2394;
+        static Object sf2395;
+        static Object sf2396;
+        static Object sf2397;
+        static Object sf2398;
+        static Object sf2399;
+        static Object sf2400;
+        static Object sf2401;
+        static Object sf2402;
+        static Object sf2403;
+        static Object sf2404;
+        static Object sf2405;
+        static Object sf2406;
+        static Object sf2407;
+        static Object sf2408;
+        static Object sf2409;
+        static Object sf2410;
+        static Object sf2411;
+        static Object sf2412;
+        static Object sf2413;
+        static Object sf2414;
+        static Object sf2415;
+        static Object sf2416;
+        static Object sf2417;
+        static Object sf2418;
+        static Object sf2419;
+        static Object sf2420;
+        static Object sf2421;
+        static Object sf2422;
+        static Object sf2423;
+        static Object sf2424;
+        static Object sf2425;
+        static Object sf2426;
+        static Object sf2427;
+        static Object sf2428;
+        static Object sf2429;
+        static Object sf2430;
+        static Object sf2431;
+        static Object sf2432;
+        static Object sf2433;
+        static Object sf2434;
+        static Object sf2435;
+        static Object sf2436;
+        static Object sf2437;
+        static Object sf2438;
+        static Object sf2439;
+        static Object sf2440;
+        static Object sf2441;
+        static Object sf2442;
+        static Object sf2443;
+        static Object sf2444;
+        static Object sf2445;
+        static Object sf2446;
+        static Object sf2447;
+        static Object sf2448;
+        static Object sf2449;
+        static Object sf2450;
+        static Object sf2451;
+        static Object sf2452;
+        static Object sf2453;
+        static Object sf2454;
+        static Object sf2455;
+        static Object sf2456;
+        static Object sf2457;
+        static Object sf2458;
+        static Object sf2459;
+        static Object sf2460;
+        static Object sf2461;
+        static Object sf2462;
+        static Object sf2463;
+        static Object sf2464;
+        static Object sf2465;
+        static Object sf2466;
+        static Object sf2467;
+        static Object sf2468;
+        static Object sf2469;
+        static Object sf2470;
+        static Object sf2471;
+        static Object sf2472;
+        static Object sf2473;
+        static Object sf2474;
+        static Object sf2475;
+        static Object sf2476;
+        static Object sf2477;
+        static Object sf2478;
+        static Object sf2479;
+        static Object sf2480;
+        static Object sf2481;
+        static Object sf2482;
+        static Object sf2483;
+        static Object sf2484;
+        static Object sf2485;
+        static Object sf2486;
+        static Object sf2487;
+        static Object sf2488;
+        static Object sf2489;
+        static Object sf2490;
+        static Object sf2491;
+        static Object sf2492;
+        static Object sf2493;
+        static Object sf2494;
+        static Object sf2495;
+        static Object sf2496;
+        static Object sf2497;
+        static Object sf2498;
+        static Object sf2499;
+        static Object sf2500;
+        static Object sf2501;
+        static Object sf2502;
+        static Object sf2503;
+        static Object sf2504;
+        static Object sf2505;
+        static Object sf2506;
+        static Object sf2507;
+        static Object sf2508;
+        static Object sf2509;
+        static Object sf2510;
+        static Object sf2511;
+        static Object sf2512;
+        static Object sf2513;
+        static Object sf2514;
+        static Object sf2515;
+        static Object sf2516;
+        static Object sf2517;
+        static Object sf2518;
+        static Object sf2519;
+        static Object sf2520;
+        static Object sf2521;
+        static Object sf2522;
+        static Object sf2523;
+        static Object sf2524;
+        static Object sf2525;
+        static Object sf2526;
+        static Object sf2527;
+        static Object sf2528;
+        static Object sf2529;
+        static Object sf2530;
+        static Object sf2531;
+        static Object sf2532;
+        static Object sf2533;
+        static Object sf2534;
+        static Object sf2535;
+        static Object sf2536;
+        static Object sf2537;
+        static Object sf2538;
+        static Object sf2539;
+        static Object sf2540;
+        static Object sf2541;
+        static Object sf2542;
+        static Object sf2543;
+        static Object sf2544;
+        static Object sf2545;
+        static Object sf2546;
+        static Object sf2547;
+        static Object sf2548;
+        static Object sf2549;
+        static Object sf2550;
+        static Object sf2551;
+        static Object sf2552;
+        static Object sf2553;
+        static Object sf2554;
+        static Object sf2555;
+        static Object sf2556;
+        static Object sf2557;
+        static Object sf2558;
+        static Object sf2559;
+        static Object sf2560;
+        static Object sf2561;
+        static Object sf2562;
+        static Object sf2563;
+        static Object sf2564;
+        static Object sf2565;
+        static Object sf2566;
+        static Object sf2567;
+        static Object sf2568;
+        static Object sf2569;
+        static Object sf2570;
+        static Object sf2571;
+        static Object sf2572;
+        static Object sf2573;
+        static Object sf2574;
+        static Object sf2575;
+        static Object sf2576;
+        static Object sf2577;
+        static Object sf2578;
+        static Object sf2579;
+        static Object sf2580;
+        static Object sf2581;
+        static Object sf2582;
+        static Object sf2583;
+        static Object sf2584;
+        static Object sf2585;
+        static Object sf2586;
+        static Object sf2587;
+        static Object sf2588;
+        static Object sf2589;
+        static Object sf2590;
+        static Object sf2591;
+        static Object sf2592;
+        static Object sf2593;
+        static Object sf2594;
+        static Object sf2595;
+        static Object sf2596;
+        static Object sf2597;
+        static Object sf2598;
+        static Object sf2599;
+        static Object sf2600;
+        static Object sf2601;
+        static Object sf2602;
+        static Object sf2603;
+        static Object sf2604;
+        static Object sf2605;
+        static Object sf2606;
+        static Object sf2607;
+        static Object sf2608;
+        static Object sf2609;
+        static Object sf2610;
+        static Object sf2611;
+        static Object sf2612;
+        static Object sf2613;
+        static Object sf2614;
+        static Object sf2615;
+        static Object sf2616;
+        static Object sf2617;
+        static Object sf2618;
+        static Object sf2619;
+        static Object sf2620;
+        static Object sf2621;
+        static Object sf2622;
+        static Object sf2623;
+        static Object sf2624;
+        static Object sf2625;
+        static Object sf2626;
+        static Object sf2627;
+        static Object sf2628;
+        static Object sf2629;
+        static Object sf2630;
+        static Object sf2631;
+        static Object sf2632;
+        static Object sf2633;
+        static Object sf2634;
+        static Object sf2635;
+        static Object sf2636;
+        static Object sf2637;
+        static Object sf2638;
+        static Object sf2639;
+        static Object sf2640;
+        static Object sf2641;
+        static Object sf2642;
+        static Object sf2643;
+        static Object sf2644;
+        static Object sf2645;
+        static Object sf2646;
+        static Object sf2647;
+        static Object sf2648;
+        static Object sf2649;
+        static Object sf2650;
+        static Object sf2651;
+        static Object sf2652;
+        static Object sf2653;
+        static Object sf2654;
+        static Object sf2655;
+        static Object sf2656;
+        static Object sf2657;
+        static Object sf2658;
+        static Object sf2659;
+        static Object sf2660;
+        static Object sf2661;
+        static Object sf2662;
+        static Object sf2663;
+        static Object sf2664;
+        static Object sf2665;
+        static Object sf2666;
+        static Object sf2667;
+        static Object sf2668;
+        static Object sf2669;
+        static Object sf2670;
+        static Object sf2671;
+        static Object sf2672;
+        static Object sf2673;
+        static Object sf2674;
+        static Object sf2675;
+        static Object sf2676;
+        static Object sf2677;
+        static Object sf2678;
+        static Object sf2679;
+        static Object sf2680;
+        static Object sf2681;
+        static Object sf2682;
+        static Object sf2683;
+        static Object sf2684;
+        static Object sf2685;
+        static Object sf2686;
+        static Object sf2687;
+        static Object sf2688;
+        static Object sf2689;
+        static Object sf2690;
+        static Object sf2691;
+        static Object sf2692;
+        static Object sf2693;
+        static Object sf2694;
+        static Object sf2695;
+        static Object sf2696;
+        static Object sf2697;
+        static Object sf2698;
+        static Object sf2699;
+        static Object sf2700;
+        static Object sf2701;
+        static Object sf2702;
+        static Object sf2703;
+        static Object sf2704;
+        static Object sf2705;
+        static Object sf2706;
+        static Object sf2707;
+        static Object sf2708;
+        static Object sf2709;
+        static Object sf2710;
+        static Object sf2711;
+        static Object sf2712;
+        static Object sf2713;
+        static Object sf2714;
+        static Object sf2715;
+        static Object sf2716;
+        static Object sf2717;
+        static Object sf2718;
+        static Object sf2719;
+        static Object sf2720;
+        static Object sf2721;
+        static Object sf2722;
+        static Object sf2723;
+        static Object sf2724;
+        static Object sf2725;
+        static Object sf2726;
+        static Object sf2727;
+        static Object sf2728;
+        static Object sf2729;
+        static Object sf2730;
+        static Object sf2731;
+        static Object sf2732;
+        static Object sf2733;
+        static Object sf2734;
+        static Object sf2735;
+        static Object sf2736;
+        static Object sf2737;
+        static Object sf2738;
+        static Object sf2739;
+        static Object sf2740;
+        static Object sf2741;
+        static Object sf2742;
+        static Object sf2743;
+        static Object sf2744;
+        static Object sf2745;
+        static Object sf2746;
+        static Object sf2747;
+        static Object sf2748;
+        static Object sf2749;
+        static Object sf2750;
+        static Object sf2751;
+        static Object sf2752;
+        static Object sf2753;
+        static Object sf2754;
+        static Object sf2755;
+        static Object sf2756;
+        static Object sf2757;
+        static Object sf2758;
+        static Object sf2759;
+        static Object sf2760;
+        static Object sf2761;
+        static Object sf2762;
+        static Object sf2763;
+        static Object sf2764;
+        static Object sf2765;
+        static Object sf2766;
+        static Object sf2767;
+        static Object sf2768;
+        static Object sf2769;
+        static Object sf2770;
+        static Object sf2771;
+        static Object sf2772;
+        static Object sf2773;
+        static Object sf2774;
+        static Object sf2775;
+        static Object sf2776;
+        static Object sf2777;
+        static Object sf2778;
+        static Object sf2779;
+        static Object sf2780;
+        static Object sf2781;
+        static Object sf2782;
+        static Object sf2783;
+        static Object sf2784;
+        static Object sf2785;
+        static Object sf2786;
+        static Object sf2787;
+        static Object sf2788;
+        static Object sf2789;
+        static Object sf2790;
+        static Object sf2791;
+        static Object sf2792;
+        static Object sf2793;
+        static Object sf2794;
+        static Object sf2795;
+        static Object sf2796;
+        static Object sf2797;
+        static Object sf2798;
+        static Object sf2799;
+        static Object sf2800;
+        static Object sf2801;
+        static Object sf2802;
+        static Object sf2803;
+        static Object sf2804;
+        static Object sf2805;
+        static Object sf2806;
+        static Object sf2807;
+        static Object sf2808;
+        static Object sf2809;
+        static Object sf2810;
+        static Object sf2811;
+        static Object sf2812;
+        static Object sf2813;
+        static Object sf2814;
+        static Object sf2815;
+        static Object sf2816;
+        static Object sf2817;
+        static Object sf2818;
+        static Object sf2819;
+        static Object sf2820;
+        static Object sf2821;
+        static Object sf2822;
+        static Object sf2823;
+        static Object sf2824;
+        static Object sf2825;
+        static Object sf2826;
+        static Object sf2827;
+        static Object sf2828;
+        static Object sf2829;
+        static Object sf2830;
+        static Object sf2831;
+        static Object sf2832;
+        static Object sf2833;
+        static Object sf2834;
+        static Object sf2835;
+        static Object sf2836;
+        static Object sf2837;
+        static Object sf2838;
+        static Object sf2839;
+        static Object sf2840;
+        static Object sf2841;
+        static Object sf2842;
+        static Object sf2843;
+        static Object sf2844;
+        static Object sf2845;
+        static Object sf2846;
+        static Object sf2847;
+        static Object sf2848;
+        static Object sf2849;
+        static Object sf2850;
+        static Object sf2851;
+        static Object sf2852;
+        static Object sf2853;
+        static Object sf2854;
+        static Object sf2855;
+        static Object sf2856;
+        static Object sf2857;
+        static Object sf2858;
+        static Object sf2859;
+        static Object sf2860;
+        static Object sf2861;
+        static Object sf2862;
+        static Object sf2863;
+        static Object sf2864;
+        static Object sf2865;
+        static Object sf2866;
+        static Object sf2867;
+        static Object sf2868;
+        static Object sf2869;
+        static Object sf2870;
+        static Object sf2871;
+        static Object sf2872;
+        static Object sf2873;
+        static Object sf2874;
+        static Object sf2875;
+        static Object sf2876;
+        static Object sf2877;
+        static Object sf2878;
+        static Object sf2879;
+        static Object sf2880;
+        static Object sf2881;
+        static Object sf2882;
+        static Object sf2883;
+        static Object sf2884;
+        static Object sf2885;
+        static Object sf2886;
+        static Object sf2887;
+        static Object sf2888;
+        static Object sf2889;
+        static Object sf2890;
+        static Object sf2891;
+        static Object sf2892;
+        static Object sf2893;
+        static Object sf2894;
+        static Object sf2895;
+        static Object sf2896;
+        static Object sf2897;
+        static Object sf2898;
+        static Object sf2899;
+        static Object sf2900;
+        static Object sf2901;
+        static Object sf2902;
+        static Object sf2903;
+        static Object sf2904;
+        static Object sf2905;
+        static Object sf2906;
+        static Object sf2907;
+        static Object sf2908;
+        static Object sf2909;
+        static Object sf2910;
+        static Object sf2911;
+        static Object sf2912;
+        static Object sf2913;
+        static Object sf2914;
+        static Object sf2915;
+        static Object sf2916;
+        static Object sf2917;
+        static Object sf2918;
+        static Object sf2919;
+        static Object sf2920;
+        static Object sf2921;
+        static Object sf2922;
+        static Object sf2923;
+        static Object sf2924;
+        static Object sf2925;
+        static Object sf2926;
+        static Object sf2927;
+        static Object sf2928;
+        static Object sf2929;
+        static Object sf2930;
+        static Object sf2931;
+        static Object sf2932;
+        static Object sf2933;
+        static Object sf2934;
+        static Object sf2935;
+        static Object sf2936;
+        static Object sf2937;
+        static Object sf2938;
+        static Object sf2939;
+        static Object sf2940;
+        static Object sf2941;
+        static Object sf2942;
+        static Object sf2943;
+        static Object sf2944;
+        static Object sf2945;
+        static Object sf2946;
+        static Object sf2947;
+        static Object sf2948;
+        static Object sf2949;
+        static Object sf2950;
+        static Object sf2951;
+        static Object sf2952;
+        static Object sf2953;
+        static Object sf2954;
+        static Object sf2955;
+        static Object sf2956;
+        static Object sf2957;
+        static Object sf2958;
+        static Object sf2959;
+        static Object sf2960;
+        static Object sf2961;
+        static Object sf2962;
+        static Object sf2963;
+        static Object sf2964;
+        static Object sf2965;
+        static Object sf2966;
+        static Object sf2967;
+        static Object sf2968;
+        static Object sf2969;
+        static Object sf2970;
+        static Object sf2971;
+        static Object sf2972;
+        static Object sf2973;
+        static Object sf2974;
+        static Object sf2975;
+        static Object sf2976;
+        static Object sf2977;
+        static Object sf2978;
+        static Object sf2979;
+        static Object sf2980;
+        static Object sf2981;
+        static Object sf2982;
+        static Object sf2983;
+        static Object sf2984;
+        static Object sf2985;
+        static Object sf2986;
+        static Object sf2987;
+        static Object sf2988;
+        static Object sf2989;
+        static Object sf2990;
+        static Object sf2991;
+        static Object sf2992;
+        static Object sf2993;
+        static Object sf2994;
+        static Object sf2995;
+        static Object sf2996;
+        static Object sf2997;
+        static Object sf2998;
+        static Object sf2999;
+        static Object sf3000;
+    }
+
+}
diff --git a/test/410-floats/src/Main.java b/test/410-floats/src/Main.java
index d8d6fac..2300457 100644
--- a/test/410-floats/src/Main.java
+++ b/test/410-floats/src/Main.java
@@ -17,9 +17,10 @@
 public class Main {
   public static void main(String[] args) {
     assertEquals(4.2f, returnFloat());
-    float[] a = new float[1];
+    float[] a = new float[2];
     a[0] = 42.2f;
-    assertEquals(42.2f, returnFloat(a));
+    a[1] = 3.2f;
+    assertEquals(45.4f, returnFloat(a));
 
     assertEquals(4.4, returnDouble());
     double[] b = new double[1];
@@ -36,6 +37,9 @@
     assertEquals(3.1, invokeTakeADouble(3.1));
     assertEquals(12.7, invokeTakeThreeDouble(3.1, 4.4, 5.2));
     assertEquals(12.7f, invokeTakeThreeFloat(3.1f, 4.4f, 5.2f));
+
+    testArrayOperations(new float[2], 0, 1.2f, 3.4f);
+    testArrayOperations(new double[2], 0, 4.1, 7.6);
   }
 
   public static float invokeReturnFloat() {
@@ -51,7 +55,7 @@
   }
 
   public static float returnFloat(float[] a) {
-    return a[0];
+    return a[0] + a[1];
   }
 
   public static double returnDouble() {
@@ -94,6 +98,34 @@
     return takeThreeFloat(a, b, c);
   }
 
+  // Test simple operations on a float array to ensure the register allocator works
+  // properly.
+  public static void testArrayOperations(float[] a, int index, float value1, float value2) {
+    a[0] = value1;
+    a[1] = value2;
+    assertEquals(value1 + value2, a[0] + a[1]);
+    a[0] = 0.0f;
+    a[1] = 0.0f;
+    assertEquals(0.0f, a[0] + a[1]);
+    a[index] = value1;
+    a[index + 1] = value2;
+    assertEquals(value1 + value2, a[0] + a[1]);
+  }
+
+  // Test simple operations on a double array to ensure the register allocator works
+  // properly.
+  public static void testArrayOperations(double[] a, int index, double value1, double value2) {
+    a[0] = value1;
+    a[1] = value2;
+    assertEquals(value1 + value2, a[0] + a[1]);
+    a[0] = 0.0;
+    a[1] = 0.0;
+    assertEquals(0.0, a[0] + a[1]);
+    a[index] = value1;
+    a[index + 1] = value2;
+    assertEquals(value1 + value2, a[0] + a[1]);
+  }
+
   public static void assertEquals(float expected, float actual) {
     if (expected != actual) {
       throw new AssertionError("Expected " + expected + " got " + actual);
diff --git a/test/411-optimizing-arith/expected.txt b/test/411-optimizing-arith/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/411-optimizing-arith/expected.txt
diff --git a/test/411-optimizing-arith/info.txt b/test/411-optimizing-arith/info.txt
new file mode 100644
index 0000000..1015551
--- /dev/null
+++ b/test/411-optimizing-arith/info.txt
@@ -0,0 +1 @@
+Tests for basic arithmethic operations.
diff --git a/test/411-optimizing-arith/src/Main.java b/test/411-optimizing-arith/src/Main.java
new file mode 100644
index 0000000..4de2271
--- /dev/null
+++ b/test/411-optimizing-arith/src/Main.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+// Note that $opt$ is a marker for the optimizing compiler to ensure
+// it does compile the method.
+public class Main {
+
+  public static void expectEquals(int expected, int result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void expectEquals(long expected, long result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void expectEquals(float expected, float result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void expectEquals(double expected, double result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void expectApproxEquals(float a, float b, float maxDelta) {
+    boolean aproxEquals = (a > b)
+      ? ((a - b) < maxDelta)
+      : ((b - a) < maxDelta);
+    if (!aproxEquals) {
+      throw new Error("Expected: " + a + ", found: " + b + ", with delta: " + maxDelta);
+    }
+  }
+
+  public static void expectApproxEquals(double a, double b, double maxDelta) {
+    boolean aproxEquals = (a > b)
+      ? ((a - b) < maxDelta)
+      : ((b - a) < maxDelta);
+    if (!aproxEquals) {
+      throw new Error("Expected: " + a + ", found: " + b + ", with delta: " + maxDelta);
+    }
+  }
+
+  public static void expectNaN(float a) {
+    if (a == a) {
+      throw new Error("Expected NaN: " + a);
+    }
+  }
+
+  public static void expectNaN(double a) {
+    if (a == a) {
+      throw new Error("Expected NaN: " + a);
+    }
+  }
+
+  public static void main(String[] args) {
+    mul();
+    neg();
+  }
+
+  public static void mul() {
+    mulInt();
+    mulLong();
+    mulFloat();
+    mulDouble();
+  }
+
+  private static void mulInt() {
+    expectEquals(15, $opt$Mul(5, 3));
+    expectEquals(0, $opt$Mul(0, 0));
+    expectEquals(0, $opt$Mul(0, 3));
+    expectEquals(0, $opt$Mul(3, 0));
+    expectEquals(-3, $opt$Mul(1, -3));
+    expectEquals(36, $opt$Mul(-12, -3));
+    expectEquals(33, $opt$Mul(1, 3) * 11);
+    expectEquals(671088645, $opt$Mul(134217729, 5)); // (2^27 + 1) * 5
+  }
+
+  private static void mulLong() {
+    expectEquals(15L, $opt$Mul(5L, 3L));
+    expectEquals(0L, $opt$Mul(0L, 0L));
+    expectEquals(0L, $opt$Mul(0L, 3L));
+    expectEquals(0L, $opt$Mul(3L, 0L));
+    expectEquals(-3L, $opt$Mul(1L, -3L));
+    expectEquals(36L, $opt$Mul(-12L, -3L));
+    expectEquals(33L, $opt$Mul(1L, 3L) * 11F);
+    expectEquals(240518168583L, $opt$Mul(34359738369L, 7L)); // (2^35 + 1) * 7
+  }
+
+  private static void mulFloat() {
+    expectApproxEquals(15F, $opt$Mul(5F, 3F), 0.0001F);
+    expectApproxEquals(0F, $opt$Mul(0F, 0F), 0.0001F);
+    expectApproxEquals(0F, $opt$Mul(0F, 3F), 0.0001F);
+    expectApproxEquals(0F, $opt$Mul(3F, 0F), 0.0001F);
+    expectApproxEquals(-3F, $opt$Mul(1F, -3F), 0.0001F);
+    expectApproxEquals(36F, $opt$Mul(-12F, -3F), 0.0001F);
+    expectApproxEquals(33F, $opt$Mul(1F, 3F) * 11F, 0.0001F);
+    expectApproxEquals(0.02F, 0.1F * 0.2F, 0.0001F);
+    expectApproxEquals(-0.1F, -0.5F * 0.2F, 0.0001F);
+
+    expectNaN($opt$Mul(0F, Float.POSITIVE_INFINITY));
+    expectNaN($opt$Mul(0F, Float.NEGATIVE_INFINITY));
+    expectNaN($opt$Mul(Float.NaN, 11F));
+    expectNaN($opt$Mul(Float.NaN, -11F));
+    expectNaN($opt$Mul(Float.NaN, Float.NEGATIVE_INFINITY));
+    expectNaN($opt$Mul(Float.NaN, Float.POSITIVE_INFINITY));
+
+    expectEquals(Float.POSITIVE_INFINITY, $opt$Mul(2F, 3.40282346638528860e+38F));
+    expectEquals(Float.POSITIVE_INFINITY, $opt$Mul(2F, Float.POSITIVE_INFINITY));
+    expectEquals(Float.NEGATIVE_INFINITY, $opt$Mul(-2F, Float.POSITIVE_INFINITY));
+    expectEquals(Float.NEGATIVE_INFINITY, $opt$Mul(-2F, 3.40282346638528860e+38F));
+    expectEquals(Float.NEGATIVE_INFINITY, $opt$Mul(2F, Float.NEGATIVE_INFINITY));
+    expectEquals(Float.POSITIVE_INFINITY, $opt$Mul(-2F, Float.NEGATIVE_INFINITY));
+    expectEquals(Float.NEGATIVE_INFINITY, $opt$Mul(Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY));
+    expectEquals(Float.POSITIVE_INFINITY, $opt$Mul(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY));
+    expectEquals(Float.POSITIVE_INFINITY, $opt$Mul(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY));
+  }
+
+  private static void mulDouble() {
+    expectApproxEquals(15D, $opt$Mul(5D, 3D), 0.0001D);
+    expectApproxEquals(0D, $opt$Mul(0D, 0D), 0.0001D);
+    expectApproxEquals(0D, $opt$Mul(0D, 3D), 0.0001D);
+    expectApproxEquals(0D, $opt$Mul(3D, 0D), 0.0001D);
+    expectApproxEquals(-3D, $opt$Mul(1D, -3D), 0.0001D);
+    expectApproxEquals(36D, $opt$Mul(-12D, -3D), 0.0001D);
+    expectApproxEquals(33D, $opt$Mul(1D, 3D) * 11D, 0.0001D);
+    expectApproxEquals(0.02D, 0.1D * 0.2D, 0.0001D);
+    expectApproxEquals(-0.1D, -0.5D * 0.2D, 0.0001D);
+
+    expectNaN($opt$Mul(0D, Double.POSITIVE_INFINITY));
+    expectNaN($opt$Mul(0D, Double.NEGATIVE_INFINITY));
+    expectNaN($opt$Mul(Double.NaN, 11D));
+    expectNaN($opt$Mul(Double.NaN, -11D));
+    expectNaN($opt$Mul(Double.NaN, Double.NEGATIVE_INFINITY));
+    expectNaN($opt$Mul(Double.NaN, Double.POSITIVE_INFINITY));
+
+    expectEquals(Double.POSITIVE_INFINITY, $opt$Mul(2D, 1.79769313486231570e+308));
+    expectEquals(Double.POSITIVE_INFINITY, $opt$Mul(2D, Double.POSITIVE_INFINITY));
+    expectEquals(Double.NEGATIVE_INFINITY, $opt$Mul(-2D, Double.POSITIVE_INFINITY));
+    expectEquals(Double.NEGATIVE_INFINITY, $opt$Mul(-2D, 1.79769313486231570e+308));
+    expectEquals(Double.NEGATIVE_INFINITY, $opt$Mul(2D, Double.NEGATIVE_INFINITY));
+    expectEquals(Double.POSITIVE_INFINITY, $opt$Mul(-2D, Double.NEGATIVE_INFINITY));
+    expectEquals(Double.NEGATIVE_INFINITY, $opt$Mul(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY));
+    expectEquals(Double.POSITIVE_INFINITY, $opt$Mul(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY));
+    expectEquals(Double.POSITIVE_INFINITY, $opt$Mul(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY));
+  }
+
+  public static void neg() {
+    expectEquals(-1, $opt$Neg(1));
+    expectEquals(1, $opt$Neg(-1));
+    expectEquals(0, $opt$Neg(0));
+    expectEquals(51, $opt$Neg(-51));
+    expectEquals(-51, $opt$Neg(51));
+    expectEquals(2147483647, $opt$Neg(-2147483647));  // (2^31 - 1)
+    expectEquals(-2147483647, $opt$Neg(2147483647));  // -(2^31 - 1)
+    // From the Java 7 SE Edition specification:
+    // http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.15.4
+    //
+    //   For integer values, negation is the same as subtraction from
+    //   zero.  The Java programming language uses two's-complement
+    //   representation for integers, and the range of two's-complement
+    //   values is not symmetric, so negation of the maximum negative
+    //   int or long results in that same maximum negative number.
+    //   Overflow occurs in this case, but no exception is thrown.
+    //   For all integer values x, -x equals (~x)+1.''
+    expectEquals(-2147483648, $opt$Neg(-2147483648)); // -(2^31)
+
+    $opt$InplaceNegOne(1);
+  }
+
+  public static void $opt$InplaceNegOne(int a) {
+    a = -a;
+    expectEquals(-1, a);
+  }
+
+  static int $opt$Mul(int a, int b) {
+    return a * b;
+  }
+
+  static long $opt$Mul(long a, long b) {
+    return a * b;
+  }
+
+  static float $opt$Mul(float a, float b) {
+    return a * b;
+  }
+
+  static double $opt$Mul(double a, double b) {
+    return a * b;
+  }
+
+  static int $opt$Neg(int a){
+    return -a;
+  }
+
+}
diff --git a/test/412-new-array/expected.txt b/test/412-new-array/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/412-new-array/expected.txt
diff --git a/test/412-new-array/info.txt b/test/412-new-array/info.txt
new file mode 100644
index 0000000..cb388b6
--- /dev/null
+++ b/test/412-new-array/info.txt
@@ -0,0 +1 @@
+Simple tests for new-array, filled-new-array and fill-array-data.
diff --git a/test/412-new-array/smali/fill_array_data.smali b/test/412-new-array/smali/fill_array_data.smali
new file mode 100644
index 0000000..34776db
--- /dev/null
+++ b/test/412-new-array/smali/fill_array_data.smali
@@ -0,0 +1,81 @@
+.class public LFillArrayData;
+
+.super Ljava/lang/Object;
+
+.method public static intArray([I)V
+   .registers 1
+
+   fill-array-data v0, :ArrayData
+   return-void
+
+:ArrayData
+    .array-data 4
+        1 2 3 4 5
+    .end array-data
+
+.end method
+
+.method public static shortArray([S)V
+   .registers 1
+
+   fill-array-data v0, :ArrayData
+   return-void
+
+:ArrayData
+    .array-data 2
+        1 2 3 4 5
+    .end array-data
+
+.end method
+
+.method public static charArray([C)V
+   .registers 1
+
+   fill-array-data v0, :ArrayData
+   return-void
+
+:ArrayData
+    .array-data 2
+        1 2 3 4 5
+    .end array-data
+
+.end method
+
+.method public static byteArray([B)V
+   .registers 1
+
+   fill-array-data v0, :ArrayData
+   return-void
+
+:ArrayData
+    .array-data 1
+        1 2 3 4 5
+    .end array-data
+
+.end method
+
+.method public static booleanArray([Z)V
+   .registers 1
+
+   fill-array-data v0, :ArrayData
+   return-void
+
+:ArrayData
+    .array-data 1
+        0 1 1
+    .end array-data
+
+.end method
+
+.method public static longArray([J)V
+   .registers 1
+
+   fill-array-data v0, :ArrayData
+   return-void
+
+:ArrayData
+    .array-data 8
+        1 2 3 4 5
+    .end array-data
+
+.end method
diff --git a/test/412-new-array/smali/filled_new_array.smali b/test/412-new-array/smali/filled_new_array.smali
new file mode 100644
index 0000000..ed8683a
--- /dev/null
+++ b/test/412-new-array/smali/filled_new_array.smali
@@ -0,0 +1,45 @@
+.class public LFilledNewArray;
+
+.super Ljava/lang/Object;
+
+.method public static newInt(III)[I
+   .registers 4
+   filled-new-array {v1, v2, v3}, [I
+   move-result-object v0
+   return-object v0
+.end method
+
+.method public static newRef(Ljava/lang/Object;Ljava/lang/Object;)[Ljava/lang/Object;
+   .registers 3
+   filled-new-array {v1, v2}, [Ljava/lang/Object;
+   move-result-object v0
+   return-object v0
+.end method
+
+.method public static newArray([I[I)[[I
+   .registers 3
+   filled-new-array {v1, v2}, [[I
+   move-result-object v0
+   return-object v0
+.end method
+
+.method public static newIntRange(III)[I
+   .registers 4
+   filled-new-array/range {v1 .. v3}, [I
+   move-result-object v0
+   return-object v0
+.end method
+
+.method public static newRefRange(Ljava/lang/Object;Ljava/lang/Object;)[Ljava/lang/Object;
+   .registers 3
+   filled-new-array/range {v1 .. v2}, [Ljava/lang/Object;
+   move-result-object v0
+   return-object v0
+.end method
+
+.method public static newArrayRange([I[I)[[I
+   .registers 3
+   filled-new-array/range {v1 .. v2}, [[I
+   move-result-object v0
+   return-object v0
+.end method
diff --git a/test/412-new-array/smali/filled_new_array_verify_error.smali b/test/412-new-array/smali/filled_new_array_verify_error.smali
new file mode 100644
index 0000000..b1470ec
--- /dev/null
+++ b/test/412-new-array/smali/filled_new_array_verify_error.smali
@@ -0,0 +1,10 @@
+.class public LFilledNewArrayVerifyError;
+
+.super Ljava/lang/Object;
+
+.method public static newRef(Ljava/lang/Object;Ljava/lang/Object;)[Ljava/lang/Object;
+   .registers 3
+   filled-new-array {v1, v2}, [Ljava/lang/Integer;
+   move-result-object v0
+   return-object v0
+.end method
diff --git a/test/412-new-array/src/Main.java b/test/412-new-array/src/Main.java
new file mode 100644
index 0000000..3c74275
--- /dev/null
+++ b/test/412-new-array/src/Main.java
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+// Note that $opt$ is a marker for the optimizing compiler to ensure
+// it does compile the method.
+
+public class Main extends TestCase {
+  public static void main(String[] args) throws Exception {
+    $opt$TestAllocations();
+    $opt$TestWithInitializations();
+    testSmaliFilledNewArray();
+    testSmaliFillArrayData();
+    testSmaliVerifyError();
+  }
+
+  static void $opt$TestAllocations() {
+    float[] a = new float[1];
+    assertEquals(1, a.length);
+
+    double[] b = new double[2];
+    assertEquals(2, b.length);
+
+    long[] c = new long[3];
+    assertEquals(3, c.length);
+
+    int[] d = new int[4];
+    assertEquals(4, d.length);
+
+    short[] e = new short[5];
+    assertEquals(5, e.length);
+
+    char[] f = new char[6];
+    assertEquals(6, f.length);
+
+    byte[] g = new byte[7];
+    assertEquals(7, g.length);
+
+    boolean[] h = new boolean[8];
+    assertEquals(8, h.length);
+
+    Object[] i = new Object[9];
+    assertEquals(9, i.length);
+  }
+
+  static void $opt$TestWithInitializations() {
+    float[] a = { 1.2f };
+    assertEquals(1, a.length);
+    assertEquals(1.2f, a[0]);
+
+    double[] b = { 4.3, 1.2 };
+    assertEquals(2, b.length);
+    assertEquals(4.3, b[0]);
+    assertEquals(1.2, b[1]);
+
+    long[] c = { 4L, 5L };
+    assertEquals(2, c.length);
+    assertEquals(4L, c[0]);
+    assertEquals(5L, c[1]);
+
+    int[] d = {1, 2, 3};
+    assertEquals(3, d.length);
+    assertEquals(1, d[0]);
+    assertEquals(2, d[1]);
+    assertEquals(3, d[2]);
+
+    short[] e = {4, 5, 6};
+    assertEquals(3, e.length);
+    assertEquals(4, e[0]);
+    assertEquals(5, e[1]);
+    assertEquals(6, e[2]);
+
+    char[] f = {'a', 'b'};
+    assertEquals(2, f.length);
+    assertEquals('a', f[0]);
+    assertEquals('b', f[1]);
+
+    byte[] g = {7, 8, 9};
+    assertEquals(3, g.length);
+    assertEquals(7, g[0]);
+    assertEquals(8, g[1]);
+    assertEquals(9, g[2]);
+
+    boolean[] h = {true, false};
+    assertEquals(2, h.length);
+    assertEquals(true, h[0]);
+    assertEquals(false, h[1]);
+
+    Object obj1 = new Object();
+    Object obj2 = new Object();
+    Object[] i = {obj1, obj2};
+    assertEquals(2, i.length);
+    assertEquals(obj1, i[0]);
+    assertEquals(obj2, i[1]);
+  }
+
+  public static void testSmaliFilledNewArray() throws Exception {
+    Class<?> c = Class.forName("FilledNewArray");
+
+    {
+      Method m = c.getMethod("newInt", Integer.TYPE, Integer.TYPE, Integer.TYPE);
+      Object[] args = {new Integer(1), new Integer(2), new Integer(3)};
+      int[] result = (int[])m.invoke(null, args);
+      assertEquals(3, result.length);
+      assertEquals(1, result[0]);
+      assertEquals(2, result[1]);
+      assertEquals(3, result[2]);
+    }
+
+    {
+      Method m = c.getMethod("newRef", Object.class, Object.class);
+      Object[] args = {new Integer(1), new Integer(2)};
+      Object[] result = (Object[])m.invoke(null, args);
+      assertEquals(2, result.length);
+      assertEquals(args[0], result[0]);
+      assertEquals(args[1], result[1]);
+    }
+
+    {
+      Method m = c.getMethod("newArray", int[].class, int[].class);
+      Object[] args = {new int[0], new int[1]};
+      Object[] result = (Object[])m.invoke(null, args);
+      assertEquals(2, result.length);
+      assertEquals(args[0], result[0]);
+      assertEquals(args[1], result[1]);
+    }
+
+    {
+      Method m = c.getMethod("newIntRange", Integer.TYPE, Integer.TYPE, Integer.TYPE);
+      Object[] args = {new Integer(1), new Integer(2), new Integer(3)};
+      int[] result = (int[])m.invoke(null, args);
+      assertEquals(3, result.length);
+      assertEquals(1, result[0]);
+      assertEquals(2, result[1]);
+      assertEquals(3, result[2]);
+    }
+
+    {
+      Method m = c.getMethod("newRefRange", Object.class, Object.class);
+      Object[] args = {new Integer(1), new Integer(2)};
+      Object[] result = (Object[])m.invoke(null, args);
+      assertEquals(2, result.length);
+      assertEquals(args[0], result[0]);
+      assertEquals(args[1], result[1]);
+    }
+
+    {
+      Method m = c.getMethod("newArrayRange", int[].class, int[].class);
+      Object[] args = {new int[0], new int[1]};
+      Object[] result = (Object[])m.invoke(null, args);
+      assertEquals(2, result.length);
+      assertEquals(args[0], result[0]);
+      assertEquals(args[1], result[1]);
+    }
+  }
+
+  public static void testSmaliVerifyError() throws Exception {
+    Error error = null;
+    // Ensure the elements in filled-new-array must be assignable
+    // to the array component type.
+    try {
+      Class.forName("FilledNewArrayVerifyError");
+    } catch (VerifyError e) {
+      error = e;
+    }
+    assertNotNull(error);
+  }
+
+  public static void testSmaliFillArrayData() throws Exception {
+    Class<?> c = Class.forName("FillArrayData");
+    {
+      Method m = c.getMethod("intArray", int[].class);
+      int[] array = new int[7];
+      Object[] args = { array };
+      m.invoke(null, args);
+      assertEquals(7, array.length);
+      assertEquals(1, array[0]);
+      assertEquals(2, array[1]);
+      assertEquals(3, array[2]);
+      assertEquals(4, array[3]);
+      assertEquals(5, array[4]);
+      assertEquals(0, array[5]);
+      assertEquals(0, array[6]);
+
+      array = new int[2];
+      args[0] = array;
+      Throwable exception  = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof IndexOutOfBoundsException);
+      }
+      assertNotNull(exception);
+      exception = null;
+      // Test that nothing has been written to the array.
+      assertEquals(0, array[0]);
+      assertEquals(0, array[1]);
+
+      args[0] = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof NullPointerException);
+      }
+      assertNotNull(exception);
+    }
+
+    {
+      Method m = c.getMethod("shortArray", short[].class);
+      short[] array = new short[7];
+      Object[] args = { array };
+      m.invoke(null, args);
+      assertEquals(7, array.length);
+      assertEquals(1, array[0]);
+      assertEquals(2, array[1]);
+      assertEquals(3, array[2]);
+      assertEquals(4, array[3]);
+      assertEquals(5, array[4]);
+      assertEquals(0, array[5]);
+      assertEquals(0, array[6]);
+
+      array = new short[2];
+      args[0] = array;
+      Throwable exception  = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof IndexOutOfBoundsException);
+      }
+      assertNotNull(exception);
+      exception = null;
+      // Test that nothing has been written to the array.
+      assertEquals(0, array[0]);
+      assertEquals(0, array[1]);
+
+      args[0] = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof NullPointerException);
+      }
+      assertNotNull(exception);
+    }
+
+    {
+      Method m = c.getMethod("longArray", long[].class);
+      long[] array = new long[7];
+      Object[] args = { array };
+      m.invoke(null, args);
+      assertEquals(7, array.length);
+      assertEquals(1L, array[0]);
+      assertEquals(2L, array[1]);
+      assertEquals(3L, array[2]);
+      assertEquals(4L, array[3]);
+      assertEquals(5L, array[4]);
+      assertEquals(0L, array[5]);
+      assertEquals(0L, array[6]);
+
+      array = new long[2];
+      args[0] = array;
+      Throwable exception  = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof IndexOutOfBoundsException);
+      }
+      assertNotNull(exception);
+      exception = null;
+      // Test that nothing has been written to the array.
+      assertEquals(0, array[0]);
+      assertEquals(0, array[1]);
+
+      args[0] = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof NullPointerException);
+      }
+      assertNotNull(exception);
+    }
+
+    {
+      Method m = c.getMethod("charArray", char[].class);
+      char[] array = new char[7];
+      Object[] args = { array };
+      m.invoke(null, args);
+      assertEquals(7, array.length);
+      assertEquals(1, array[0]);
+      assertEquals(2, array[1]);
+      assertEquals(3, array[2]);
+      assertEquals(4, array[3]);
+      assertEquals(5, array[4]);
+      assertEquals(0, array[5]);
+      assertEquals(0, array[6]);
+
+      array = new char[2];
+      args[0] = array;
+      Throwable exception  = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof IndexOutOfBoundsException);
+      }
+      assertNotNull(exception);
+      exception = null;
+      // Test that nothing has been written to the array.
+      assertEquals(0, array[0]);
+      assertEquals(0, array[1]);
+
+      args[0] = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof NullPointerException);
+      }
+      assertNotNull(exception);
+    }
+
+    {
+      Method m = c.getMethod("byteArray", byte[].class);
+      byte[] array = new byte[7];
+      Object[] args = { array };
+      m.invoke(null, args);
+      assertEquals(7, array.length);
+      assertEquals(1, array[0]);
+      assertEquals(2, array[1]);
+      assertEquals(3, array[2]);
+      assertEquals(4, array[3]);
+      assertEquals(5, array[4]);
+      assertEquals(0, array[5]);
+      assertEquals(0, array[6]);
+
+      array = new byte[2];
+      args[0] = array;
+      Throwable exception  = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof IndexOutOfBoundsException);
+      }
+      assertNotNull(exception);
+      exception = null;
+      // Test that nothing has been written to the array.
+      assertEquals(0, array[0]);
+      assertEquals(0, array[1]);
+
+      args[0] = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof NullPointerException);
+      }
+      assertNotNull(exception);
+    }
+
+    {
+      Method m = c.getMethod("booleanArray", boolean[].class);
+      boolean[] array = new boolean[5];
+      Object[] args = { array };
+      m.invoke(null, args);
+      assertEquals(5, array.length);
+      assertEquals(false, array[0]);
+      assertEquals(true, array[1]);
+      assertEquals(true, array[2]);
+      assertEquals(false, array[3]);
+      assertEquals(false, array[4]);
+
+      array = new boolean[2];
+      args[0] = array;
+      Throwable exception  = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof IndexOutOfBoundsException);
+      }
+      assertNotNull(exception);
+      exception = null;
+      // Test that nothing has been written to the array.
+      assertEquals(false, array[0]);
+      assertEquals(false, array[1]);
+
+      args[0] = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof NullPointerException);
+      }
+      assertNotNull(exception);
+    }
+  }
+}
diff --git a/test/412-new-array/src/TestCase.java b/test/412-new-array/src/TestCase.java
new file mode 100644
index 0000000..ef77f71
--- /dev/null
+++ b/test/412-new-array/src/TestCase.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+/**
+ * Common superclass for test cases.
+ */
+
+import java.util.Arrays;
+
+public abstract class TestCase {
+  public static void assertSame(Object expected, Object value) {
+    if (expected != value) {
+      throw new AssertionError("Objects are not the same: expected " +
+          String.valueOf(expected) + ", got " + String.valueOf(value));
+    }
+  }
+
+  public static void assertNotSame(Object expected, Object value) {
+    if (expected == value) {
+      throw new AssertionError(
+          "Objects are the same: " + String.valueOf(expected));
+    }
+  }
+
+  public static void assertEquals(String message, int expected, int actual) {
+    if (expected != actual) {
+      throw new AssertionError(message);
+    }
+  }
+
+  public static void assertEquals(int expected, int actual) {
+    if (expected != actual) {
+      throw new AssertionError("Expected " + expected + " got " + actual);
+    }
+  }
+
+  public static void assertTrue(String message, boolean condition) {
+    if (!condition) {
+      throw new AssertionError(message);
+    }
+  }
+
+  public static void assertTrue(boolean condition) {
+    assertTrue("Expected true", condition);
+  }
+
+  public static void assertFalse(String message, boolean condition) {
+    if (condition) {
+      throw new AssertionError(message);
+    }
+  }
+
+  public static void assertFalse(boolean condition) {
+    assertFalse("Expected false", condition);
+  }
+
+  public static void assertEquals(Object expected, Object actual) {
+    if (!expected.equals(actual)) {
+      String msg = "Expected \"" + expected + "\" but got \"" + actual + "\"";
+      throw new AssertionError(msg);
+    }
+  }
+
+  public static void assertNotEquals(int expected, int actual) {
+    if (expected == actual) {
+      throw new AssertionError("Expected " + expected + " got " + actual);
+    }
+  }
+
+  public static void assertNotEquals(Object expected, Object actual) {
+    if (expected.equals(actual)) {
+      String msg = "Objects are the same: " + String.valueOf(expected);
+      throw new AssertionError(msg);
+    }
+  }
+
+  public static <T> void assertArrayEquals(T[] actual, T... expected) {
+      assertTrue(Arrays.equals(expected, actual));
+  }
+
+  public static void assertEquals(
+      String message, Object expected, Object actual) {
+    if (!expected.equals(actual)) {
+      throw new AssertionError(message);
+    }
+  }
+
+  public static void assertEquals(
+      String message, long expected, long actual) {
+    if (expected != actual) {
+      throw new AssertionError(message);
+    }
+  }
+
+  public static void assertEquals(long expected, long actual) {
+    if (expected != actual) {
+      throw new AssertionError("Expected " + expected + " got " + actual);
+    }
+  }
+
+  public static void assertEquals(
+      String message, boolean expected, boolean actual) {
+    if (expected != actual) {
+      throw new AssertionError(message);
+    }
+  }
+
+  public static void assertEquals(boolean expected, boolean actual) {
+    if (expected != actual) {
+      throw new AssertionError("Expected " + expected + " got " + actual);
+    }
+  }
+
+  public static void assertEquals(
+      String message, float expected, float actual) {
+    if (expected != actual) {
+      throw new AssertionError(message);
+    }
+  }
+
+  public static void assertEquals(float expected, float actual) {
+    if (expected != actual) {
+      throw new AssertionError("Expected " + expected + " got " + actual);
+    }
+  }
+
+  public static void assertEquals(float expected, float actual,
+                                  float tolerance) {
+    if ((actual < expected - tolerance) || (expected + tolerance < actual)) {
+      throw new AssertionError("Expected " + expected + " got " + actual +
+          " tolerance " + tolerance);
+    }
+  }
+
+  public static void assertEquals(
+      String message, double expected, double actual) {
+    if (expected != actual) {
+      throw new AssertionError(message);
+    }
+  }
+
+  public static void assertEquals(double expected, double actual) {
+    if (expected != actual) {
+      throw new AssertionError("Expected " + expected + " got " + actual);
+    }
+  }
+
+  public static void assertEquals(double expected, double actual,
+                                  double tolerance) {
+    if ((actual < expected - tolerance) || (expected + tolerance < actual)) {
+      throw new AssertionError("Expected " + expected + " got " + actual +
+          " tolerance " + tolerance);
+    }
+  }
+
+  public static void assertSame(
+      String message, Object expected, Object actual) {
+    if (expected != actual) {
+      throw new AssertionError(message);
+    }
+  }
+
+  public static void assertNull(String message, Object object) {
+    if (object != null) {
+      throw new AssertionError(message);
+    }
+  }
+
+  public static void assertNull(Object object) {
+    assertNull("Expected null", object);
+  }
+
+  public static void assertNotNull(String message, Object object) {
+    if (object == null) {
+      throw new AssertionError(message);
+    }
+  }
+
+  public static void assertNotNull(Object object) {
+    assertNotNull("Expected non-null", object);
+  }
+
+  public static void fail(String msg) {
+    throw new AssertionError(msg);
+  }
+}
diff --git a/test/413-regalloc-regression/expected.txt b/test/413-regalloc-regression/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/413-regalloc-regression/expected.txt
diff --git a/test/413-regalloc-regression/info.txt b/test/413-regalloc-regression/info.txt
new file mode 100644
index 0000000..c706c1d
--- /dev/null
+++ b/test/413-regalloc-regression/info.txt
@@ -0,0 +1,2 @@
+Regression test for the linear scan register allocator, that use to
+fail compiling removeElementAt in x86.
diff --git a/test/413-regalloc-regression/src/Main.java b/test/413-regalloc-regression/src/Main.java
new file mode 100644
index 0000000..3e649f8
--- /dev/null
+++ b/test/413-regalloc-regression/src/Main.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+public class Main {
+  private Object[] data;
+  private int size;
+
+  public Main() {
+    data = new Object[4];
+    size = 0;
+  }
+
+  public void removeElementAt(int index) {
+    for (int i = index; i < size - 1; i++) {
+      data[i] = data[i + 1];
+    }
+    data[--size] = null;
+  }
+
+  public static void main(String[] args) {
+    Main main = new Main();
+    main.size++;
+    main.removeElementAt(0);
+    if (main.size != 0) {
+      throw new Error("Unexpected size");
+    }
+  }
+}
diff --git a/test/414-optimizing-arith-sub/expected.txt b/test/414-optimizing-arith-sub/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/414-optimizing-arith-sub/expected.txt
diff --git a/test/414-optimizing-arith-sub/info.txt b/test/414-optimizing-arith-sub/info.txt
new file mode 100644
index 0000000..1eaa148
--- /dev/null
+++ b/test/414-optimizing-arith-sub/info.txt
@@ -0,0 +1 @@
+Subtraction tests.
diff --git a/test/414-optimizing-arith-sub/src/Main.java b/test/414-optimizing-arith-sub/src/Main.java
new file mode 100644
index 0000000..30e8436
--- /dev/null
+++ b/test/414-optimizing-arith-sub/src/Main.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+// Note that $opt$ is a marker for the optimizing compiler to ensure
+// it does compile the method.
+public class Main {
+
+  public static void expectEquals(int expected, int result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void expectEquals(long expected, long result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void expectEquals(float expected, float result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void expectEquals(double expected, double result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void expectApproxEquals(float a, float b) {
+    float maxDelta = 0.0001F;
+    boolean aproxEquals = (a > b) ? ((a - b) < maxDelta) : ((b - a) < maxDelta);
+    if (!aproxEquals) {
+      throw new Error("Expected: " + a + ", found: " + b + ", with delta: " + maxDelta + " " + (a - b));
+    }
+  }
+
+  public static void expectApproxEquals(double a, double b) {
+    double maxDelta = 0.00001D;
+    boolean aproxEquals = (a > b) ? ((a - b) < maxDelta) : ((b - a) < maxDelta);
+    if (!aproxEquals) {
+      throw new Error("Expected: " + a + ", found: " + b + ", with delta: " + maxDelta + " " + (a - b));
+    }
+  }
+
+  public static void expectNaN(float a) {
+    if (a == a) {
+      throw new Error("Expected NaN: " + a);
+    }
+  }
+
+  public static void expectNaN(double a) {
+    if (a == a) {
+      throw new Error("Expected NaN: " + a);
+    }
+  }
+
+  public static void main(String[] args) {
+    subInt();
+    subLong();
+    subFloat();
+    subDouble();
+  }
+
+  private static void subInt() {
+    expectEquals(2, $opt$Sub(5, 3));
+    expectEquals(0, $opt$Sub(0, 0));
+    expectEquals(-3, $opt$Sub(0, 3));
+    expectEquals(3, $opt$Sub(3, 0));
+    expectEquals(4, $opt$Sub(1, -3));
+    expectEquals(-9, $opt$Sub(-12, -3));
+    expectEquals(134217724, $opt$Sub(134217729, 5)); // (2^27 + 1) - 5
+  }
+
+  private static void subLong() {
+    expectEquals(2L, $opt$Sub(5L, 3L));
+    expectEquals(0L, $opt$Sub(0L, 0L));
+    expectEquals(-3L, $opt$Sub(0L, 3L));
+    expectEquals(3L, $opt$Sub(3L, 0L));
+    expectEquals(4L, $opt$Sub(1L, -3L));
+    expectEquals(-9L, $opt$Sub(-12L, -3L));
+    expectEquals(134217724L, $opt$Sub(134217729L, 5L)); // (2^27 + 1) - 5
+    expectEquals(34359738362L, $opt$Sub(34359738369L, 7L)); // (2^35 + 1) - 7
+  }
+
+  private static void subFloat() {
+    expectApproxEquals(2F, $opt$Sub(5F, 3F));
+    expectApproxEquals(0F, $opt$Sub(0F, 0F));
+    expectApproxEquals(-3F, $opt$Sub(0F, 3F));
+    expectApproxEquals(3F, $opt$Sub(3F, 0F));
+    expectApproxEquals(4F, $opt$Sub(1F, -3F));
+    expectApproxEquals(-9F, $opt$Sub(-12F, -3F));
+    expectApproxEquals(34359738362F, $opt$Sub(34359738369F, 7F)); // (2^35 + 1) - 7
+    expectApproxEquals(-0.1F, $opt$Sub(0.1F, 0.2F));
+    expectApproxEquals(0.2F, $opt$Sub(-0.5F, -0.7F));
+
+    expectNaN($opt$Sub(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY));
+    expectNaN($opt$Sub(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY));
+    expectNaN($opt$Sub(Float.NaN, 11F));
+    expectNaN($opt$Sub(Float.NaN, -11F));
+    expectNaN($opt$Sub(Float.NaN, Float.NEGATIVE_INFINITY));
+    expectNaN($opt$Sub(Float.NaN, Float.POSITIVE_INFINITY));
+
+    expectEquals(Float.NEGATIVE_INFINITY, $opt$Sub(-Float.MAX_VALUE, Float.MAX_VALUE));
+    expectEquals(Float.NEGATIVE_INFINITY, $opt$Sub(2F, Float.POSITIVE_INFINITY));
+    expectEquals(Float.POSITIVE_INFINITY, $opt$Sub(Float.MAX_VALUE, -Float.MAX_VALUE));
+    expectEquals(Float.POSITIVE_INFINITY, $opt$Sub(2F, Float.NEGATIVE_INFINITY));
+    expectEquals(Float.POSITIVE_INFINITY, $opt$Sub(Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY));
+    expectEquals(Float.NEGATIVE_INFINITY, $opt$Sub(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY));
+  }
+
+  private static void subDouble() {
+    expectApproxEquals(2D, $opt$Sub(5D, 3D));
+    expectApproxEquals(0D, $opt$Sub(0D, 0D));
+    expectApproxEquals(-3D, $opt$Sub(0D, 3D));
+    expectApproxEquals(3D, $opt$Sub(3D, 0D));
+    expectApproxEquals(4D, $opt$Sub(1D, -3D));
+    expectApproxEquals(-9D, $opt$Sub(-12D, -3D));
+    expectApproxEquals(134217724D, $opt$Sub(134217729D, 5D)); // (2^27 + 1) - 5
+    expectApproxEquals(34359738362D, $opt$Sub(34359738369D, 7D)); // (2^35 + 1) - 7
+    expectApproxEquals(-0.1D, $opt$Sub(0.1D, 0.2D));
+    expectApproxEquals(0.2D, $opt$Sub(-0.5D, -0.7D));
+
+    expectNaN($opt$Sub(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY));
+    expectNaN($opt$Sub(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY));
+    expectNaN($opt$Sub(Double.NaN, 11D));
+    expectNaN($opt$Sub(Double.NaN, -11D));
+    expectNaN($opt$Sub(Double.NaN, Double.NEGATIVE_INFINITY));
+    expectNaN($opt$Sub(Double.NaN, Double.POSITIVE_INFINITY));
+
+    expectEquals(Double.NEGATIVE_INFINITY, $opt$Sub(-Double.MAX_VALUE, Double.MAX_VALUE));
+    expectEquals(Double.NEGATIVE_INFINITY, $opt$Sub(2D, Double.POSITIVE_INFINITY));
+    expectEquals(Double.POSITIVE_INFINITY, $opt$Sub(Double.MAX_VALUE, -Double.MAX_VALUE));
+    expectEquals(Double.POSITIVE_INFINITY, $opt$Sub(2D, Double.NEGATIVE_INFINITY));
+    expectEquals(Double.POSITIVE_INFINITY, $opt$Sub(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY));
+    expectEquals(Double.NEGATIVE_INFINITY, $opt$Sub(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
+  }
+
+  static int $opt$Sub(int a, int b) {
+    return a - b;
+  }
+
+  static long $opt$Sub(long a, long b) {
+    return a - b;
+  }
+
+  static float $opt$Sub(float a, float b) {
+    return a - b;
+  }
+
+  static double $opt$Sub(double a, double b) {
+    return a - b;
+  }
+
+}
diff --git a/test/800-smali/info.txt b/test/800-smali/info.txt
index cfcc230..3022962 100644
--- a/test/800-smali/info.txt
+++ b/test/800-smali/info.txt
@@ -1,4 +1,4 @@
 Smali-based tests.
-Will compile and run all the smali files in src/ and run the test cases mentioned in src/Main.java.
+Will compile and run all the smali files in smali/ and run the test cases mentioned in src/Main.java.
 
 Obviously needs to run under Dalvik or ART.
diff --git a/test/800-smali/src/b_17790197.smali b/test/800-smali/smali/b_17790197.smali
similarity index 100%
rename from test/800-smali/src/b_17790197.smali
rename to test/800-smali/smali/b_17790197.smali
diff --git a/test/Android.libarttest.mk b/test/Android.libarttest.mk
index 2d139a6..55de1f3 100644
--- a/test/Android.libarttest.mk
+++ b/test/Android.libarttest.mk
@@ -58,8 +58,7 @@
   ifeq ($$(art_target_or_host),target)
     $(call set-target-local-clang-vars)
     $(call set-target-local-cflags-vars,debug)
-    LOCAL_SHARED_LIBRARIES += libdl libcutils
-    LOCAL_STATIC_LIBRARIES := libgtest
+    LOCAL_SHARED_LIBRARIES += libdl
     LOCAL_MULTILIB := both
     LOCAL_MODULE_PATH_32 := $(ART_TARGET_TEST_OUT)/$(ART_TARGET_ARCH_32)
     LOCAL_MODULE_PATH_64 := $(ART_TARGET_TEST_OUT)/$(ART_TARGET_ARCH_64)
@@ -68,11 +67,7 @@
   else # host
     LOCAL_CLANG := $(ART_HOST_CLANG)
     LOCAL_CFLAGS := $(ART_HOST_CFLAGS) $(ART_HOST_DEBUG_CFLAGS)
-    LOCAL_STATIC_LIBRARIES := libcutils
-    LOCAL_LDLIBS += -ldl -lpthread
-    ifeq ($(HOST_OS),linux)
-      LOCAL_LDLIBS += -lrt
-    endif
+    LOCAL_LDLIBS := $(ART_HOST_LDLIBS) -ldl -lpthread
     LOCAL_IS_HOST_MODULE := true
     LOCAL_MULTILIB := both
     include $(BUILD_HOST_SHARED_LIBRARY)
diff --git a/test/Android.libnativebridgetest.mk b/test/Android.libnativebridgetest.mk
index dd7255a..1b20e69 100644
--- a/test/Android.libnativebridgetest.mk
+++ b/test/Android.libnativebridgetest.mk
@@ -51,7 +51,7 @@
   ifeq ($$(art_target_or_host),target)
     $(call set-target-local-clang-vars)
     $(call set-target-local-cflags-vars,debug)
-    LOCAL_SHARED_LIBRARIES += libdl libcutils
+    LOCAL_SHARED_LIBRARIES += libdl
     LOCAL_STATIC_LIBRARIES := libgtest
     LOCAL_MULTILIB := both
     LOCAL_MODULE_PATH_32 := $(ART_TARGET_TEST_OUT)/$(ART_TARGET_ARCH_32)
@@ -62,7 +62,7 @@
     LOCAL_CLANG := $(ART_HOST_CLANG)
     LOCAL_CFLAGS := $(ART_HOST_CFLAGS) $(ART_HOST_DEBUG_CFLAGS)
     LOCAL_STATIC_LIBRARIES := libcutils
-    LOCAL_LDLIBS += -ldl -lpthread
+    LOCAL_LDLIBS := $(ART_HOST_LDLIBS) -ldl -lpthread
     ifeq ($(HOST_OS),linux)
       LOCAL_LDLIBS += -lrt
     endif
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 9082b47..6822825 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -52,7 +52,7 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE_TAGS := tests
 LOCAL_MODULE := art-run-tests
-LOCAL_ADDITIONAL_DEPENDENCIES := $(TEST_ART_RUN_TEST_BUILD_RULES) smali dexmerger
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TEST_ART_RUN_TEST_BUILD_RULES)
 # The build system use this flag to pick up files generated by declare-make-art-run-test.
 LOCAL_PICKUP_FILES := $(art_run_tests_dir)
 
@@ -66,11 +66,6 @@
 ########################################################################
 # General rules to build and run a run-test.
 
-# Test rule names or of the form:
-# test-art-{1: host or target}-run-test-{2: prebuild no-prebuild no-dex2oat}-
-#    {3: interpreter default optimizing}-{4: relocate no-relocate relocate-no-patchoat}-
-#    {5: trace or no-trace}-{6: gcstress gcverify cms}-{7: forcecopy checkjni jni}-
-#    {8: no-image or image}-{9: test name}{10: 32 or 64}
 TARGET_TYPES := host target
 PREBUILD_TYPES := prebuild
 ifeq ($(ART_TEST_RUN_TEST_NO_PREBUILD),true)
@@ -115,6 +110,13 @@
 ifeq ($(ART_TEST_RUN_TEST_NO_IMAGE),true)
   IMAGE_TYPES += no-image
 endif
+RUN_TYPES :=
+ifeq ($(ART_TEST_RUN_TEST_DEBUG),true)
+  RUN_TYPES += debug
+endif
+ifeq ($(ART_TEST_RUN_TEST_NDEBUG),true)
+  RUN_TYPES += ndebug
+endif
 ADDRESS_SIZES_TARGET := $(ART_PHONY_TEST_TARGET_SUFFIX) $(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
 ADDRESS_SIZES_HOST := $(ART_PHONY_TEST_HOST_SUFFIX) $(2ND_ART_PHONY_TEST_HOST_SUFFIX)
 ALL_ADDRESS_SIZES := 64 32
@@ -122,21 +124,22 @@
 # List all run test names with number arguments agreeing with the comment above.
 define all-run-test-names
   $(foreach target, $(1), \
-    $(foreach prebuild, $(2), \
-      $(foreach compiler, $(3), \
-        $(foreach relocate, $(4), \
-          $(foreach trace, $(5), \
-            $(foreach gc, $(6), \
-              $(foreach jni, $(7), \
-                $(foreach image, $(8), \
-                  $(foreach test, $(9), \
-                    $(foreach address_size, $(10), \
-                      test-art-$(target)-run-test-$(prebuild)-$(compiler)-$(relocate)-$(trace)-$(gc)-$(jni)-$(image)-$(test)$(address_size) \
-                  ))))))))))
+    $(foreach run-type, $(2), \
+      $(foreach prebuild, $(3), \
+        $(foreach compiler, $(4), \
+          $(foreach relocate, $(5), \
+            $(foreach trace, $(6), \
+              $(foreach gc, $(7), \
+                $(foreach jni, $(8), \
+                  $(foreach image, $(9), \
+                    $(foreach test, $(10), \
+                      $(foreach address_size, $(11), \
+                        test-art-$(target)-run-test-$(run-type)-$(prebuild)-$(compiler)-$(relocate)-$(trace)-$(gc)-$(jni)-$(image)-$(test)$(address_size) \
+                    )))))))))))
 endef  # all-run-test-names
 
 # To generate a full list or tests:
-# $(call all-run-test-names,$(TARGET_TYPES),$(PREBUILD_TYPES),$(COMPILER_TYPES), \
+# $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES),$(COMPILER_TYPES), \
 #        $(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES),$(IMAGE_TYPES), \
 #        $(TEST_ART_RUN_TESTS), $(ALL_ADDRESS_SIZES))
 
@@ -152,7 +155,7 @@
 
  # disable timing sensitive tests on "dist" builds.
 ifdef dist_goal
-  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(PREBUILD_TYPES), \
+  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
         $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
         $(IMAGE_TYPES), $(TEST_ART_TIMING_SENSITIVE_RUN_TESTS), $(ALL_ADDRESS_SIZES))
 endif
@@ -162,7 +165,7 @@
 TEST_ART_BROKEN_RUN_TESTS := \
   004-ThreadStress
 
-ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(PREBUILD_TYPES), \
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
       $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
       $(IMAGE_TYPES), $(TEST_ART_BROKEN_RUN_TESTS), $(ALL_ADDRESS_SIZES))
 
@@ -173,7 +176,7 @@
   116-nodex2oat
 
 ifneq (,$(filter prebuild,$(PREBUILD_TYPES)))
-  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),prebuild, \
+  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),prebuild, \
       $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
       $(IMAGE_TYPES), $(TEST_ART_BROKEN_PREBUILD_RUN_TESTS), $(ALL_ADDRESS_SIZES))
 endif
@@ -184,7 +187,7 @@
   117-nopatchoat
 
 ifneq (,$(filter no-prebuild,$(PREBUILD_TYPES)))
-  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),no-prebuild, \
+  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),no-prebuild, \
       $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
       $(IMAGE_TYPES), $(TEST_ART_BROKEN_NO_PREBUILD_TESTS), $(ALL_ADDRESS_SIZES))
 endif
@@ -197,7 +200,7 @@
   117-nopatchoat
 
 ifneq (,$(filter no-relocate,$(RELOCATE_TYPES)))
-  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(PREBUILD_TYPES), \
+  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
       $(COMPILER_TYPES), no-relocate,$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
       $(IMAGE_TYPES), $(TEST_ART_BROKEN_NO_RELOCATE_TESTS), $(ALL_ADDRESS_SIZES))
 endif
@@ -210,7 +213,7 @@
   114-ParallelGC
 
 ifneq (,$(filter gcstress,$(GC_TYPES)))
-  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(PREBUILD_TYPES), \
+  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
       $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),gcstress,$(JNI_TYPES), \
       $(IMAGE_TYPES), $(TEST_ART_BROKEN_GCSTRESS_RUN_TESTS), $(ALL_ADDRESS_SIZES))
 endif
@@ -218,7 +221,7 @@
 TEST_ART_BROKEN_GCSTRESS_RUN_TESTS :=
 
 # 115-native-bridge setup is complicated. Need to implement it correctly for the target.
-ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(PREBUILD_TYPES),$(COMPILER_TYPES), \
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES),$(COMPILER_TYPES), \
     $(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES),$(IMAGE_TYPES),115-native-bridge, \
     $(ALL_ADDRESS_SIZES))
 
@@ -232,26 +235,100 @@
   119-noimage-patchoat
 
 ifneq (,$(filter no-dex2oat,$(PREBUILD_TYPES)))
-  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),no-dex2oat, \
+  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),no-dex2oat, \
       $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES),$(IMAGE_TYPES), \
       $(TEST_ART_BROKEN_FALLBACK_RUN_TESTS),$(ALL_ADDRESS_SIZES))
 endif
 
 
 ifneq (,$(filter no-image,$(IMAGE_TYPES)))
-  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(PREBUILD_TYPES), \
+  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
       $(COMPILER_TYPES), $(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES),no-image, \
       $(TEST_ART_BROKEN_FALLBACK_RUN_TESTS),$(ALL_ADDRESS_SIZES))
 endif
 
 ifneq (,$(filter relocate-no-patchoat,$(RELOCATE_TYPES)))
-  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(PREBUILD_TYPES), \
+  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
       $(COMPILER_TYPES), relocate-no-patchoat,$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
       $(IMAGE_TYPES),$(TEST_ART_BROKEN_FALLBACK_RUN_TESTS),$(ALL_ADDRESS_SIZES))
 endif
 
 TEST_ART_BROKEN_FALLBACK_RUN_TESTS :=
 
+# The following tests use libarttest.so, which is linked against libartd.so, so will
+# not work when libart.so is the one loaded.
+# TODO: Find a way to run these tests in ndebug mode.
+TEST_ART_BROKEN_NDEBUG_TESTS := \
+  004-JniTest \
+  004-ReferenceMap \
+  004-SignalTest \
+  004-StackWalk \
+  004-UnsafeTest \
+  115-native-bridge \
+  116-nodex2oat \
+  117-nopatchoat \
+  118-noimage-dex2oat \
+  119-noimage-patchoat \
+
+ifneq (,$(filter ndebug,$(RUN_TYPES)))
+  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),ndebug,$(PREBUILD_TYPES), \
+      $(COMPILER_TYPES), $(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES),$(IMAGE_TYPES), \
+      $(TEST_ART_BROKEN_NDEBUG_TESTS),$(ALL_ADDRESS_SIZES))
+endif
+
+TEST_ART_BROKEN_NDEBUG_TESTS :=
+
+# Known broken tests for the default compiler (Quick).
+TEST_ART_BROKEN_DEFAULT_RUN_TESTS := \
+  412-new-array
+
+ifneq (,$(filter default,$(COMPILER_TYPES)))
+  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
+      default,$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
+      $(IMAGE_TYPES),$(TEST_ART_BROKEN_DEFAULT_RUN_TESTS),$(ALL_ADDRESS_SIZES))
+endif
+
+TEST_ART_BROKEN_DEFAULT_RUN_TESTS :=
+
+# Known broken tests for the arm64 optimizing compiler backend.
+TEST_ART_BROKEN_OPTIMIZING_ARM64_RUN_TESTS := \
+  003-omnibus-opcodes \
+  006-args \
+  011-array-copy \
+  018-stack-overflow \
+  036-finalizer \
+  044-proxy \
+  070-nio-buffer \
+  072-precise-gc \
+  082-inline-execute \
+  083-compiler-regressions \
+  093-serialization \
+  096-array-copy-concurrent-gc \
+  100-reflect2 \
+  106-exceptions2 \
+  107-int-math2 \
+  121-modifiers \
+  122-npe \
+  123-compiler-regressions-mt \
+  405-optimizing-long-allocator \
+  407-arrays \
+  410-floats \
+  411-optimizing-arith \
+  412-new-array \
+  413-regalloc-regression \
+  414-optimizing-arith-sub \
+  700-LoadArgRegs \
+  800-smali
+
+ifneq (,$(filter optimizing,$(COMPILER_TYPES)))
+  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES), \
+      optimizing,$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
+      $(IMAGE_TYPES),$(TEST_ART_BROKEN_OPTIMIZING_ARM64_RUN_TESTS),64)
+endif
+
+TEST_ART_BROKEN_OPTIMIZING_ARM64_RUN_TESTS :=
+
+
 # Clear variables ahead of appending to them when defining tests.
 $(foreach target, $(TARGET_TYPES), $(eval ART_RUN_TEST_$(call name-to-var,$(target))_RULES :=))
 $(foreach target, $(TARGET_TYPES), \
@@ -281,6 +358,9 @@
 $(foreach target, $(TARGET_TYPES), \
   $(foreach address_size, $(ALL_ADDRESS_SIZES), \
     $(eval ART_RUN_TEST_$(call name-to-var,$(target))_$(call name-to-var,$(address_size))_RULES :=)))
+$(foreach target, $(TARGET_TYPES), \
+  $(foreach run_type, $(RUN_TYPES), \
+    $(eval ART_RUN_TEST_$(call name-to-var,$(target))_$(call name-to-var,$(run_type))_RULES :=)))
 
 # We need dex2oat and dalvikvm on the target as well as the core image.
 TEST_ART_TARGET_SYNC_DEPS += $(ART_TARGET_EXECUTABLES) $(TARGET_CORE_IMG_OUT) $(2ND_TARGET_CORE_IMG_OUT)
@@ -314,10 +394,10 @@
 endif
 
 # Create a rule to build and run a tests following the form:
-# test-art-{1: host or target}-run-test-{2: prebuild no-prebuild no-dex2oat}-
-#    {3: interpreter default optimizing}-{4: relocate no-relocate relocate-no-patchoat}-
-#    {5: trace or no-trace}-{6: gcstress gcverify cms}-{7: forcecopy checkjni jni}-
-#    {8: no-image image}-{9: test name}{10: 32 or 64}
+# test-art-{1: host or target}-run-test-{2: debug ndebug}-{3: prebuild no-prebuild no-dex2oat}-
+#    {4: interpreter default optimizing}-{5: relocate no-relocate relocate-no-patchoat}-
+#    {6: trace or no-trace}-{7: gcstress gcverify cms}-{8: forcecopy checkjni jni}-
+#    {9: no-image image}-{10: test name}{11: 32 or 64}
 define define-test-art-run-test
   run_test_options :=
   prereq_rule :=
@@ -340,119 +420,129 @@
       $$(error found $(1) expected $(TARGET_TYPES))
     endif
   endif
-  ifeq ($(2),prebuild)
+  ifeq ($(2),debug)
+    test_groups += ART_RUN_TEST_$$(uc_host_or_target)_DEBUG_RULES
+  else
+    ifeq ($(2),ndebug)
+      test_groups += ART_RUN_TEST_$$(uc_host_or_target)_RELEASE_RULES
+      run_test_options += -O
+    else
+      $$(error found $(2) expected $(RUN_TYPES))
+    endif
+  endif
+  ifeq ($(3),prebuild)
     test_groups += ART_RUN_TEST_$$(uc_host_or_target)_PREBUILD_RULES
     run_test_options += --prebuild
   else
-    ifeq ($(2),no-prebuild)
+    ifeq ($(3),no-prebuild)
       test_groups += ART_RUN_TEST_$$(uc_host_or_target)_NO_PREBUILD_RULES
       run_test_options += --no-prebuild
     else
-      ifeq ($(2),no-dex2oat)
+      ifeq ($(3),no-dex2oat)
         test_groups += ART_RUN_TEST_$$(uc_host_or_target)_NO_DEX2OAT_RULES
         run_test_options += --no-prebuild --no-dex2oat
       else
-        $$(error found $(2) expected $(PREBUILD_TYPES))
+        $$(error found $(3) expected $(PREBUILD_TYPES))
       endif
     endif
   endif
-  ifeq ($(3),optimizing)
+  ifeq ($(4),optimizing)
     test_groups += ART_RUN_TEST_$$(uc_host_or_target)_OPTIMIZING_RULES
     run_test_options += -Xcompiler-option --compiler-backend=Optimizing
   else
-    ifeq ($(3),interpreter)
+    ifeq ($(4),interpreter)
       test_groups += ART_RUN_TEST_$$(uc_host_or_target)_INTERPRETER_RULES
       run_test_options += --interpreter
     else
-      ifeq ($(3),default)
+      ifeq ($(4),default)
         test_groups += ART_RUN_TEST_$$(uc_host_or_target)_DEFAULT_RULES
       else
-        $$(error found $(3) expected $(COMPILER_TYPES))
+        $$(error found $(4) expected $(COMPILER_TYPES))
       endif
     endif
   endif
-  ifeq ($(4),relocate)
+  ifeq ($(5),relocate)
     test_groups += ART_RUN_TEST_$$(uc_host_or_target)_RELOCATE_RULES
     run_test_options += --relocate
   else
-    ifeq ($(4),no-relocate)
+    ifeq ($(5),no-relocate)
       test_groups += ART_RUN_TEST_$$(uc_host_or_target)_NO_RELOCATE_RULES
       run_test_options += --no-relocate
     else
-      ifeq ($(4),relocate-no-patchoat)
+      ifeq ($(5),relocate-no-patchoat)
         test_groups += ART_RUN_TEST_$$(uc_host_or_target)_RELOCATE_NO_PATCHOAT_RULES
         run_test_options += --relocate --no-patchoat
       else
-        $$(error found $(4) expected $(RELOCATE_TYPES))
+        $$(error found $(5) expected $(RELOCATE_TYPES))
       endif
     endif
   endif
-  ifeq ($(5),trace)
+  ifeq ($(6),trace)
     test_groups += ART_RUN_TEST_$$(uc_host_or_target)_TRACE_RULES
     run_test_options += --trace
   else
-    ifeq ($(5),no-trace)
+    ifeq ($(6),no-trace)
       test_groups += ART_RUN_TEST_$$(uc_host_or_target)_NO_TRACE_RULES
     else
-      $$(error found $(5) expected $(TRACE_TYPES))
+      $$(error found $(6) expected $(TRACE_TYPES))
     endif
   endif
-  ifeq ($(6),gcverify)
+  ifeq ($(7),gcverify)
     test_groups += ART_RUN_TEST_$$(uc_host_or_target)_GCVERIFY_RULES
     run_test_options += --gcverify
   else
-    ifeq ($(6),gcstress)
+    ifeq ($(7),gcstress)
       test_groups += ART_RUN_TEST_$$(uc_host_or_target)_GCSTRESS_RULES
       run_test_options += --gcstress
     else
-      ifeq ($(6),cms)
+      ifeq ($(7),cms)
         test_groups += ART_RUN_TEST_$$(uc_host_or_target)_CMS_RULES
       else
-        $$(error found $(6) expected $(GC_TYPES))
+        $$(error found $(7) expected $(GC_TYPES))
       endif
     endif
   endif
-  ifeq ($(7),forcecopy)
+  ifeq ($(8),forcecopy)
     test_groups += ART_RUN_TEST_$$(uc_host_or_target)_FORCECOPY_RULES
     run_test_options += --runtime-option -Xjniopts:forcecopy
     ifneq ($$(ART_TEST_JNI_FORCECOPY),true)
       skip_test := true
     endif
   else
-    ifeq ($(7),checkjni)
+    ifeq ($(8),checkjni)
       test_groups += ART_RUN_TEST_$$(uc_host_or_target)_CHECKJNI_RULES
       run_test_options += --runtime-option -Xcheck:jni
     else
-      ifeq ($(7),jni)
+      ifeq ($(8),jni)
         test_groups += ART_RUN_TEST_$$(uc_host_or_target)_JNI_RULES
       else
-        $$(error found $(7) expected $(JNI_TYPES))
+        $$(error found $(8) expected $(JNI_TYPES))
       endif
     endif
   endif
-  ifeq ($(8),no-image)
+  ifeq ($(9),no-image)
     test_groups += ART_RUN_TEST_$$(uc_host_or_target)_NO_IMAGE_RULES
     run_test_options += --no-image
   else
-    ifeq ($(8),image)
+    ifeq ($(9),image)
       test_groups += ART_RUN_TEST_$$(uc_host_or_target)_IMAGE_RULES
     else
-      $$(error found $(8) expected $(IMAGE_TYPES))
+      $$(error found $(9) expected $(IMAGE_TYPES))
     endif
   endif
-  # $(9) is the test name
-  test_groups += ART_RUN_TEST_$$(uc_host_or_target)_$(call name-to-var,$(9))_RULES
-  ifeq ($(10),64)
+  # $(10) is the test name
+  test_groups += ART_RUN_TEST_$$(uc_host_or_target)_$(call name-to-var,$(10))_RULES
+  ifeq ($(11),64)
     test_groups += ART_RUN_TEST_$$(uc_host_or_target)_64_RULES
     run_test_options += --64
   else
-    ifeq ($(10),32)
+    ifeq ($(11),32)
       test_groups += ART_RUN_TEST_$$(uc_host_or_target)_32_RULES
     else
-      $$(error found $(10) expected $(ALL_ADDRESS_SIZES))
+      $$(error found $(11) expected $(ALL_ADDRESS_SIZES))
     endif
   endif
-  run_test_rule_name := test-art-$(1)-run-test-$(2)-$(3)-$(4)-$(5)-$(6)-$(7)-$(8)-$(9)$(10)
+  run_test_rule_name := test-art-$(1)-run-test-$(2)-$(3)-$(4)-$(5)-$(6)-$(7)-$(8)-$(9)-$(10)$(11)
   run_test_options := --output-path $(ART_HOST_TEST_DIR)/run-test-output/$$(run_test_rule_name) \
       $$(run_test_options)
 $$(run_test_rule_name): PRIVATE_RUN_TEST_OPTIONS := $$(run_test_options)
@@ -462,7 +552,7 @@
 	  DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) \
 	    SMALI=$(abspath $(HOST_OUT_EXECUTABLES)/smali) \
 	    DXMERGER=$(abspath $(HOST_OUT_EXECUTABLES)/dexmerger) \
-	    art/test/run-test $$(PRIVATE_RUN_TEST_OPTIONS) $(9) \
+	    art/test/run-test $$(PRIVATE_RUN_TEST_OPTIONS) $(10) \
 	      && $$(call ART_TEST_PASSED,$$@) || $$(call ART_TEST_FAILED,$$@)
 	$$(hide) (echo $(MAKECMDGOALS) | grep -q $$@ && \
 	  echo "run-test run as top-level target, removing test directory $(ART_HOST_TEST_DIR)" && \
@@ -480,16 +570,17 @@
 
 $(foreach target, $(TARGET_TYPES), \
   $(foreach test, $(TEST_ART_RUN_TESTS), \
-    $(foreach address_size, $(ADDRESS_SIZES_$(call name-to-var,$(target))), \
-      $(foreach prebuild, $(PREBUILD_TYPES), \
-        $(foreach compiler, $(COMPILER_TYPES), \
-          $(foreach relocate, $(RELOCATE_TYPES), \
-            $(foreach trace, $(TRACE_TYPES), \
-              $(foreach gc, $(GC_TYPES), \
-                $(foreach jni, $(JNI_TYPES), \
-                  $(foreach image, $(IMAGE_TYPES), \
-                    $(eval $(call define-test-art-run-test,$(target),$(prebuild),$(compiler),$(relocate),$(trace),$(gc),$(jni),$(image),$(test),$(address_size))) \
-                ))))))))))
+    $(foreach run_type, $(RUN_TYPES), \
+      $(foreach address_size, $(ADDRESS_SIZES_$(call name-to-var,$(target))), \
+        $(foreach prebuild, $(PREBUILD_TYPES), \
+          $(foreach compiler, $(COMPILER_TYPES), \
+            $(foreach relocate, $(RELOCATE_TYPES), \
+              $(foreach trace, $(TRACE_TYPES), \
+                $(foreach gc, $(GC_TYPES), \
+                  $(foreach jni, $(JNI_TYPES), \
+                    $(foreach image, $(IMAGE_TYPES), \
+                      $(eval $(call define-test-art-run-test,$(target),$(run_type),$(prebuild),$(compiler),$(relocate),$(trace),$(gc),$(jni),$(image),$(test),$(address_size))) \
+                  )))))))))))
 define-test-art-run-test :=
 
 # Define a phony rule whose purpose is to test its prerequisites.
@@ -509,6 +600,9 @@
   $(foreach prebuild, $(PREBUILD_TYPES), $(eval \
     $(call define-test-art-run-test-group,test-art-$(target)-run-test-$(prebuild),$(ART_RUN_TEST_$(call name-to-var,$(target))_$(call name-to-var,$(prebuild))_RULES)))))
 $(foreach target, $(TARGET_TYPES), \
+  $(foreach run-type, $(RUN_TYPES), $(eval \
+    $(call define-test-art-run-test-group,test-art-$(target)-run-test-$(run-type),$(ART_RUN_TEST_$(call name-to-var,$(target))_$(call name-to-var,$(run-type))_RULES)))))
+$(foreach target, $(TARGET_TYPES), \
   $(foreach compiler, $(COMPILER_TYPES), $(eval \
     $(call define-test-art-run-test-group,test-art-$(target)-run-test-$(compiler),$(ART_RUN_TEST_$(call name-to-var,$(target))_$(call name-to-var,$(compiler))_RULES)))))
 $(foreach target, $(TARGET_TYPES), \
@@ -562,6 +656,9 @@
 $(foreach target, $(TARGET_TYPES), \
   $(foreach address_size, $(ALL_ADDRESS_SIZES), \
     $(eval ART_RUN_TEST_$(call name-to-var,$(target))_$(call name-to-var,$(address_size))_RULES :=)))
+$(foreach target, $(TARGET_TYPES), \
+  $(foreach run_type, $(RUN_TYPES), \
+    $(eval ART_RUN_TEST_$(call name-to-var,$(target))_$(call name-to-var,$(run_type))_RULES :=)))
 define-test-art-run-test-group :=
 TARGET_TYPES :=
 PREBUILD_TYPES :=
@@ -574,6 +671,7 @@
 ADDRESS_SIZES_TARGET :=
 ADDRESS_SIZES_HOST :=
 ALL_ADDRESS_SIZES :=
+RUN_TYPES :=
 
 include $(LOCAL_PATH)/Android.libarttest.mk
 include art/test/Android.libnativebridgetest.mk
diff --git a/test/etc/default-build b/test/etc/default-build
index faafc1f..009736b 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -26,7 +26,12 @@
 
 if [ ${NEED_DEX} = "true" ]; then
   ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
-  zip $TEST_NAME.jar classes.dex
+fi
+
+if [ -r smali ]; then
+  # Compile Smali classes
+  ${SMALI} -JXmx256m --output smali_classes.dex `find smali -name '*.smali'`
+  ${DXMERGER} classes.dex classes.dex smali_classes.dex
 fi
 
 if [ -r src-ex ]; then
@@ -43,3 +48,5 @@
     mv classes-1.dex classes.dex
   fi
 fi
+
+zip $TEST_NAME.jar classes.dex
diff --git a/test/etc/reference-run-test-classes b/test/etc/reference-run-test-classes
deleted file mode 100755
index 6f10f5a..0000000
--- a/test/etc/reference-run-test-classes
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/bin/sh
-#
-# Run the code in a classes directory on a host-local reference virtual
-# machine. The jar should contain a top-level class named Main to run.
-#
-# Options:
-#   --quiet       -- don't chatter
-#   --debug       -- wait for debugger to attach
-#   --no-verify   -- turn off verification (on by default)
-#   --dev         -- development mode
-
-msg() {
-    if [ "$QUIET" = "n" ]; then
-        echo "$@"
-    fi
-}
-
-DEBUG="n"
-QUIET="n"
-VERIFY="y"
-
-while true; do
-    if [ "x$1" = "x--quiet" ]; then
-        QUIET="y"
-        shift
-    elif [ "x$1" = "x--debug" ]; then
-        DEBUG="y"
-        shift
-    elif [ "x$1" = "x--no-verify" ]; then
-        VERIFY="n"
-        shift
-    elif [ "x$1" = "x--dev" ]; then
-        # not used; ignore
-        shift
-    elif [ "x$1" = "x--" ]; then
-        shift
-        break
-    elif expr "x$1" : "x--" >/dev/null 2>&1; then
-        echo "unknown $0 option: $1" 1>&2
-        exit 1
-    else
-        break
-    fi
-done
-
-if [ "$VERIFY" = "y" ]; then
-    VERIFY_ARG="-Xverify:all"
-    msg "Performing verification"
-else
-    VERIFY_ARG="-Xverify:none"
-    msg "Skipping verification"
-fi
-
-if [ "$DEBUG" = "y" ]; then
-    PORT=8000
-    msg "Waiting for jdb to connect:"
-    msg "    jdb -attach localhost:$PORT"
-    DEBUG_OPTS="-agentlib:jdwp=transport=dt_socket,address=$PORT,server=y,suspend=y"
-fi
-
-${JAVA} ${DEBUG_OPTS} ${VERIFY_ARG} -classpath classes Main "$@"
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 9a32ec7..82d47d7 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -32,6 +32,7 @@
 QUIET="n"
 RELOCATE="y"
 USE_GDB="n"
+USE_JVM="n"
 VERIFY="y"
 ZYGOTE=""
 MAIN=""
@@ -105,6 +106,9 @@
     elif [ "x$1" = "x--interpreter" ]; then
         INTERPRETER="y"
         shift
+    elif [ "x$1" = "x--jvm" ]; then
+        USE_JVM="y"
+        shift
     elif [ "x$1" = "x--invoke-with" ]; then
         shift
         if [ "x$1" = "x" ]; then
@@ -161,19 +165,17 @@
 
     if [ "$VERIFY" = "y" ]; then
         DEX_VERIFY=""
+        JVM_VERIFY_ARG="-Xverify:all"
         msg "Performing verification"
     else
         DEX_VERIFY="-Xverify:none"
+        JVM_VERIFY_ARG="-Xverify:none"
         msg "Skipping verification"
     fi
 fi
 
 msg "------------------------------"
 
-if [ "$HAVE_IMAGE" = "n" ]; then
-    BOOT_OPT="-Ximage:/system/non-existant/core.art"
-fi
-
 if [ "$DEBUGGER" = "y" ]; then
   # Use this instead for ddms and connect by running 'ddms':
   # DEBUGGER_OPTS="-agentlib:jdwp=transport=dt_android_adb,server=y,suspend=y"
@@ -188,6 +190,17 @@
   DEBUGGER_OPTS="-agentlib:jdwp=transport=dt_socket,address=$PORT,server=y,suspend=y"
 fi
 
+if [ "$USE_JVM" = "y" ]; then
+  ${JAVA} ${DEBUGGER_OPTS} ${JVM_VERIFY_ARG} -classpath classes $MAIN "$@"
+  exit
+fi
+
+
+if [ "$HAVE_IMAGE" = "n" ]; then
+    BOOT_OPT="-Ximage:/system/non-existant/core.art"
+fi
+
+
 if [ "$USE_GDB" = "y" ]; then
   if [ "$HOST" = "n" ]; then
     GDB="$GDB_SERVER :5039"
@@ -341,12 +354,9 @@
 
     if [ "$USE_GDB" = "y" ]; then
       # When running under gdb, we cannot do piping and grepping...
-      LD_PRELOAD=libsigchain.so $cmdline "$@"
+      $cmdline "$@"
     else
-      # If we are execing /bin/false we might not be on the same ISA as libsigchain.so
-      # ld.so will helpfully warn us of this. Unfortunately this messes up our error
-      # checking so we will just filter out the error with a grep.
-      LD_PRELOAD=libsigchain.so $cmdline "$@" 2>&1 | grep -v -E "^ERROR: ld\.so: object '.+\.so' from LD_PRELOAD cannot be preloaded.*: ignored\.$"
+      $cmdline "$@" 2>&1
       # Add extra detail if time out is enabled.
       if [ ${PIPESTATUS[0]} = 124 ] && [ "$TIME_OUT" = "y" ]; then
         echo -e "\e[91mTEST TIMED OUT!\e[0m" >&2
diff --git a/test/run-test b/test/run-test
index 3e98d6d..2ef3ab1 100755
--- a/test/run-test
+++ b/test/run-test
@@ -17,6 +17,7 @@
 # Set up prog to be the path of this script, including following symlinks,
 # and set up progdir to be the fully-qualified pathname of its directory.
 prog="$0"
+args="$@"
 while [ -h "${prog}" ]; do
     newProg=`/bin/ls -ld "${prog}"`
     newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
@@ -106,6 +107,7 @@
         runtime="jvm"
         prebuild_mode="no"
         NEED_DEX="false"
+        run_args="${run_args} --jvm"
         shift
     elif [ "x$1" = "x-O" ]; then
         lib="libart.so"
@@ -270,7 +272,6 @@
 
 if [ "$target_mode" = "no" ]; then
     if [ "$runtime" = "jvm" ]; then
-        RUN="${progdir}/etc/reference-run-test-classes"
         if [ "$prebuild_mode" = "yes" ]; then
             echo "--prebuild with --jvm is unsupported";
             exit 1;
@@ -468,9 +469,6 @@
   file_size_limit=5120
 elif echo "$test_dir" | grep 083; then
   file_size_limit=5120
-elif echo "$test_dir" | grep 115; then
-# Native bridge test copies libarttest.so into its directory, which needs 2MB already.
-  file_size_limit=5120
 fi
 if ! ulimit -S "$file_size_limit"; then
    echo "ulimit file size setting failed"
@@ -526,9 +524,10 @@
         "./${run}" $run_args "$@" >"$output" 2>&1
     else
         cp "$build_output" "$output"
-        echo "Failed to build in tmpdir=${tmp_dir} from oldwd=${oldwd} and cwd=`pwd`"
-        echo "Non-canonical tmpdir was ${noncanonical_tmp_dir}"
-        echo "build exit status: $build_exit" >>"$output"
+        echo "Failed to build in tmpdir=${tmp_dir} from oldwd=${oldwd} and cwd=`pwd`" >> "$output"
+        echo "Non-canonical tmpdir was ${noncanonical_tmp_dir}" >> "$output"
+        echo "Args: ${args}" >> "output"
+        echo "build exit status: $build_exit" >> "$output"
     fi
     ./$check_cmd "$expected" "$output"
     if [ "$?" = "0" ]; then
diff --git a/tools/art b/tools/art
index 0103071..af96b47 100644
--- a/tools/art
+++ b/tools/art
@@ -53,6 +53,12 @@
   elif [ "$1" = "--64" ]; then
     DALVIKVM=dalvikvm64
     shift
+  elif [ "$1" = "--perf" ]; then
+    PERF="record"
+    shift
+  elif [ "$1" = "--perf-report" ]; then
+    PERF="report"
+    shift
   elif expr "$1" : "--" >/dev/null 2>&1; then
     echo "unknown option: $1" 1>&2
     exit 1
@@ -68,6 +74,11 @@
 LIBDIR=$(find_libdir)
 LD_LIBRARY_PATH=$ANDROID_ROOT/$LIBDIR
 
+
+if [ z"$PERF" != z ]; then
+  invoke_with="perf record -o $ANDROID_DATA/perf.data -e cycles:u $invoke_with"
+fi
+
 mkdir -p $ANDROID_DATA/dalvik-cache/{arm,arm64,x86,x86_64}
 ANDROID_DATA=$ANDROID_DATA \
   ANDROID_ROOT=$ANDROID_ROOT \
@@ -75,7 +86,18 @@
   $invoke_with $ANDROID_ROOT/bin/$DALVIKVM $lib \
     -XXlib:$LIBART \
     -Ximage:$ANDROID_ROOT/framework/core.art \
-     "$@"
+    -Xcompiler-option --include-debug-symbols \
+    "$@"
+
 EXIT_STATUS=$?
-rm -rf $ANDROID_DATA
+
+if [ z"$PERF" != z ]; then
+  if [ z"$PERF" = zreport ]; then
+    perf report -i $ANDROID_DATA/perf.data
+  fi
+  echo "Perf data saved in: $ANDROID_DATA/perf.data"
+else
+  rm -rf $ANDROID_DATA
+fi
+
 exit $EXIT_STATUS